<p>------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------</p>
<p>&nbsp;</p>
<p>笔记一共记录了毕向东的java基础的25天课程,分上、中、下</p>
<p>本片为中篇,涵盖11-20天课程</p>

11.线程

a.线程状态图

b 线程创建 继承 Thread 或者 实现Runnable接口

c 懒汉单例

public class Single {
    private static Single s = null;
    private Single(){

    }

    public static Single getInstance(){
        if(s == null){
            synchronized (Single.class) {
                if(s == null){
                    s = new Single();
                }
            }
        }
        return s;
    }
}

d 线程死锁  同步中嵌套同步容易发生死锁

e 多线程运行安全问题

java解决方案:

同步代码块

同步的前提:

必须有两个或者两个以上的线程;必须是多个线程使用同一个锁

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,消耗资源


12.让线程锁一会儿吧

同步表现形式:

同步代码块;同步函数

同步代码块使用的锁是任意java对象;同步函数使用的锁是this;对应static的同步函数,使用的锁不是this。是类型.class该类的字节码文件。

当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2的释放。如果此时线程B在持有lock2的时候,也在试图获取lock1,因为线程A正持有lock1,因此线程B会阻塞等待A对lock1的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。

下面给出一个两个线程间产生死锁的示例,如下:

package com.itheima;

public class DeadLock {
	private String objID;
	public DeadLock(String id){
		objID = id;
	}

	public synchronized void checkOther(DeadLock other){
		print("entering checkOther");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
	    print("in checkOther() - about to " + "invoke 'other.action()'");
	    other.action();
        print("leaving checkOther()");
	}

	  public synchronized void action() {
	        print("entering action()");
	        try { Thread.sleep(500); }
	        catch ( InterruptedException x ) { }
	        print("leaving action()");
	    }  

	  public void print(String msg) {
	        threadPrint("objID=" + objID + " - " + msg);
	    }  

	  public static void threadPrint(String msg) {
	        String threadName = Thread.currentThread().getName();
	        System.out.println(threadName + ": " + msg);
	    }  

	  public static void main(String[] args) {
		  final DeadLock obj1 = new DeadLock("obj1");
	       final DeadLock obj2 = new DeadLock("obj2");  

	       Runnable runA = new Runnable() {
               public void run() {
                   obj1.checkOther(obj2);
               }
           };
       Thread threadA = new Thread(runA, "threadA");
       threadA.start();  

       try { Thread.sleep(200); }
       catch ( InterruptedException x ) { }  

       Runnable runB = new Runnable() {
               public void run() {
                   obj2.checkOther(obj1);
               }
           };
       Thread threadB = new Thread(runB, "threadB");
       threadB.start();
       try { Thread.sleep(5000); }
       catch ( InterruptedException x ) { }  

       threadPrint("finished sleeping");  

       threadPrint("about to interrupt() threadA");
       threadA.interrupt();  

       try { Thread.sleep(1000); }
       catch ( InterruptedException x ) { }  

       threadPrint("about to interrupt() threadB");
       threadB.interrupt();  

       try { Thread.sleep(1000); }
       catch ( InterruptedException x ) { }  

       threadPrint("did that break the deadlock?");
       threadPrint("no,已经发生了死锁");
	}
}

  

如何在一个线程执行过程中加入另一个线程执行,并使当前线程等待。

join:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。

调用线程run方法 和start方法的区别,看一段代码然后分析

class MyThread extends Thread{
    public void run(){
        try {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
        }
        System.out.println("MyThread running");
    }
}

public class ThreadTest{
    public static void main(String argv[]) {
        MyThread t = new MyThread();
        t.run();
        t.start();
        System.out.println("Thread Test");
      }
}

/*
代码分析过程:

MyThread t = new MyThread();
创建了一个线程。

t.run();
调用MyThread对象的run方法。
这是只有一个线程在运行就是主线程。
当主线程执行到了run方法中的sleep(3000);时。
这是主线程处于冻结状态。程序并没有任何执行。
当3秒过后,主线程打印了 MyThread running。 run方法执行结束。

t.start();
开启了t线程。
有两种可能情况。
第一种,主线程在只执行了t.start()后,还具有执行权,继续往下执行,
打印了Thread Test。主线程结束。
t线程获取执行权,调用自己的run方法。然后执行的sleep(3000);冻结3秒。
3秒后,打印MyThread running t线程结束,整个程序结束。

第二种情况:
主线程执行到t.start();开启了t线程,t线程就直接获取到了执行权。
就调用自己的run方法。
指定到sleep(3000).t线程冻结3秒,这是t线程就是释放了执行权。
那么主线程开始执行打印了Thread Test,主线程结束。
等到3秒后,t线程打印MyThread running ,然后t线程结束。
程序结束。

如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。

只要控制住循环,就可以让run方法结束,也就是线程结束。

特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。

Thread类提供该方法 interrupt();

经典线程问题:生产者与消费者

对象分析:生产者-消费者-资源

资源涉及到同步

设计资源对象

class Resource
{
    private String name;
    private int count = 1;
    private boolean flag = false;
            //  t1    t2
    public synchronized void set(String name)
    {
        while(flag)
            try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)
        this.name = name+"--"+count++;

        System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
        flag = true;
        this.notifyAll();
    }

    //  t3   t4
    public synchronized void out()
    {
        while(!flag)
            try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
        System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
        flag = false;
        this.notifyAll();
    }
}

生产者对象

class Producer implements Runnable
{
    private Resource res;

    Producer(Resource res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            res.set("+商品+");
        }
    }
}

消费者对象

class Consumer implements Runnable
{
    private Resource res;

    Consumer(Resource res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            res.out();
        }
    }
}

测试用例

class ProducerConsumerDemo
{
    public static void main(String[] args)
    {
        Resource r = new Resource();

        Producer pro = new Producer(r);
        Consumer con = new Consumer(r);

        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(pro);
        Thread t3 = new Thread(con);
        Thread t4 = new Thread(con);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

jdk1.5中提供的多线程升级解决方案:

Lock 和 Condition对象

import java.util.concurrent.locks.*;

class ProducerConsumerDemo2
{
    public static void main(String[] args)
    {
        Resource r = new Resource();

        Producer pro = new Producer(r);
        Consumer con = new Consumer(r);

        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(pro);
        Thread t3 = new Thread(con);
        Thread t4 = new Thread(con);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

/*
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
该示例中,实现了本方只唤醒对方操作。

Lock:替代了Synchronized
    lock
    unlock
    newCondition()

Condition:替代了Object wait notify notifyAll
    await();
    signal();
    signalAll();
*/
class Resource
{
    private String name;
    private int count = 1;
    private boolean flag = false;
            //  t1    t2
    private Lock lock = new ReentrantLock();

    private Condition condition_pro = lock.newCondition();
    private Condition condition_con = lock.newCondition();

    public  void set(String name)throws InterruptedException
    {
        lock.lock();
        try
        {
            while(flag)
                condition_pro.await();//t1,t2
            this.name = name+"--"+count++;

            System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
            flag = true;
            condition_con.signal();
        }
        finally
        {
            lock.unlock();//释放锁的动作一定要执行。
        }
    }

    //  t3   t4
    public  void out()throws InterruptedException
    {
        lock.lock();
        try
        {
            while(!flag)
                condition_con.await();
            System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
            flag = false;
            condition_pro.signal();
        }
        finally
        {
            lock.unlock();
        }

    }
}

class Producer implements Runnable
{
    private Resource res;

    Producer(Resource res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            try
            {
                res.set("+商品+");
            }
            catch (InterruptedException e)
            {
            }

        }
    }
}

class Consumer implements Runnable
{
    private Resource res;

    Consumer(Resource res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            try
            {
                res.out();
            }
            catch (InterruptedException e)
            {
            }
        }
    }
}

线程总结:

wait和sleep区别

wait:释放cpu执行权,释放同步中锁

sleep:释放cpu执行权,不释放同步中锁

停止线程:
stop过时。
原理:run方法结束。run方法中通常定义循环,指定控制住循环线程即可结束。

1,定义结束标记。
2,当线程处于了冻结状态,没有执行标记,程序一样无法结束。
这时可以循环,正常退出冻结状态,或者强制结束冻结状态。
强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态。
但是会发生InterruptedException异常。

线程中一些常见方法:
setDaemon(boolean):将线程标记为后台线程,后台线程和前台线程一样,开启,一样抢执行权运行,
只有在结束时,有区别,当前台线程都运行结束后,后台线程会自动结束。

join():什么意思?等待该线程结束。当A线程执行到了B的.join方法时,A就会处于冻结状态。
A什么时候运行呢?当B运行结束后,A就会具备运行资格,继续运行。

加入线程,可以完成对某个线程的临时加入执行。

yield:临时暂停,可以让线程是释放执行权。


13.数据类型

基本数据类型 ,基本数据类型包装类 ,自动装箱拆箱,特殊类型字符串

Integer m = 128;
Integer n = 128;

print("m==n:"+(m==n));false 不同的对象引用

Integer a = 127;
Integer b = 127;

print(a == b);true //当数值在byte范围内(0-127),对于新特性,如果该数值已经存在,则不会在开辟新的空间。

String s1 = "abc";//s1是一个类类型变量, "abc"是一个对象。
//字符串最大特点:一旦被初始化就不可以被改变。

String s2 = new String("abc");

//s1和s2有什么区别?
//s1在内存中有一个对象。
//s2在内存中有两个对象。

String a = "opq";
String b = "opq";
System.out.println("a==b:"+(a==b)); true

/*
获取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。
"abcwerthelloyuiodef"
"cvhellobnm"
思路:
1,将短的那个子串按照长度递减的方式获取到。
2,将每获取到的子串去长串中判断是否包含,
如果包含,已经找到!。
*/

    public static String maxSubStr(String s1, String s2){
        String maxSub = "";
        //得到短的串
        //对短的串依次遍历长度依次递减获取字串
        String max = s1.length() >= s2.length() ? s1 : s2;
        String min = max == s1 ? s2 : s1;
        for (int i = 0; i < max.length(); i++) {
            for(int j=0,k=min.length()-i ; k != min.length() +1 ;  j++,k++){
                maxSub = min.substring(j, k);
                if(max.contains(maxSub)){
                    System.out.println("同时出现的最大字串:"+maxSub);
                    return maxSub;
                }
            }
        }
        return maxSub;
    }

StringBuffer 字符串缓冲区

JDK1.5版本之后出现了StringBuilder

StringBuffer线程同步

StringBuilder线程不同步

开发建议使用StringBuilder

1.提高效率

2.简化书写

3.提高安全性


14.集合

/*
Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。

|--Set:元素是无序,元素不可以重复。、

List:
特有方法。凡是可以操作角标的方法都是该体系特有的方法。


add(index,element);
addAll(index,Collection);


remove(index);


set(index,element);

get(index):
subList(from,to);
listIterator();
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();

List集合特有的迭代器。ListIterator是Iterator的子接口。

在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。

所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,
只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。

该接口只能通过List集合的listIterator方法获取。

*/

1,add方法的参数类型是Object。以便于接收任意类型对象。

2,集合中存储的都是对象的引用(地址)

|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。

注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。

|--TreeSet:

Set集合的功能和Collection是一致的。


15.泛型

泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。

好处
1.将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,

2,避免了强制转换麻烦。

泛型格式:通过<>来定义要操作的引用数据类型。

在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,
只要见到<>就要定义泛型。

其实<> 就是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。


16.Map集合

|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。

希望打印结果:a(1)c(2).....

通过结果发现,每一个字母都有对应的次数。
说明字母和次数之间都有映射关系。

注意了,当发现有映射关系时,可以选择map集合。
因为map集合中存放就是映射关系。

因为打印结果的字母有顺序 核心就是说出使用treemap集合


17.数组操作工具类、集合操作工具类、静态导入

高级for循环

格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{

}

对集合进行遍历。
只能获取集合元素。但是不能对集合进行操作。

迭代器除了遍历,还可以进行remove集合中元素的动作。
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

传统for和高级for有什么区别呢?

高级for有一个局限性。必须有被遍历的目标。

建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义脚标。

/*
JDK1.5版本出现的新特性。

方法的可变参数。
在使用时注意:可变参数一定要定义在参数列表最后面。

*/


18.日期类和文件操作


19. 文件包装类

装饰设计模式:
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。


20. 递归  ini文件 properties

SequenceInputStream

黑马程序员----java基础笔记中(毕向东)的更多相关文章

  1. 黑马程序员----java基础笔记上(毕向东)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...

  2. 黑马程序员----java基础笔记下(毕向东)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 目录--- 21.字符编码 22.javaswig 事件 23.socket 网络通讯 24.网 ...

  3. 黑马程序员Java基础班+就业班课程笔记全发布(持续更新)

    正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G  QQ 1481135711 这是我总 ...

  4. 黑马程序员——JAVA基础之泛型和通配符

    ------- android培训.java培训.期待与您交流! ---------- 泛型:            JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...

  5. 黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象

    ------- android培训.java培训.期待与您交流! ---------- 面向对象: 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程 强调的是功能行为 面向对象 将 ...

  6. 黑马程序员——JAVA基础之语法、命名规则

    ------- android培训.java培训.期待与您交流! ---------- 1.java语言组成:关键字,标识符,注释,常量和变量,运算符,语句,函数,数组. 2.java关键字:被Jav ...

  7. 黑马程序员——JAVA基础之反射

      ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! -------     Java 反射是Java语言的一个很重要的特征,它使得Java具体了"动态 ...

  8. 黑马程序员 Java基础&lt;十八&gt;---&gt; 网路编程

    --------------- ASP.Net+Android+IO开发S..Net培训.期待与您交流! --------------- 第一  概述 一.概述: 1.网络模型:OSI参考模型和TCP ...

  9. 纯干货!耗时1个月整理黑马程序员Java教程+笔记+配套工具

    学习Java是不是很苦?找不到资料?不了解学习步骤?想要全面的线路图! 或者是找资料,前面免费,后面收费?工具软件要收费? 当当当~~今天就没有这个状态发生了!不信就证明给你看 1.学习路线图 2.J ...

随机推荐

  1. UEditor百度编辑器,工具栏上自定义添加一个普通按钮

    添加一个名叫“hougelou”的普通按钮在工具栏上: 第一步:找到ueditor.config.js文件中的toolbars数组,增加一个“hougelou”字符串,然后找到labelMap数组,对 ...

  2. ZigBee 安全探究

    ZigBee 安全探究 0x02 ZigBee安全机制 (注:对于本节内容,可能在新版ZigBee协议标准中会有所变化,请以新版为准.) ZigBee主要提供有三个等级的安全模式: 1. 非安全模式: ...

  3. python python 入门学习之网页数据爬虫cnbeta文章保存

    需求驱动学习的动力. 因为我们单位上不了外网所以读新闻是那么的痛苦,试着自己抓取网页保存下来,然后离线阅读.今天抓取的是cnbeta科技新闻,抓取地址是http://m.cnbeta.com/wap/ ...

  4. xilium CefGlue集成包

    最近很苦B的要做一个C#的HTM5项目,build了一下xilium CefGlue包,提供下载地址,供那些无法下载的同学们使用. http://yun.baidu.com/s/1slEdNEt

  5. js的隐含参数(arguments,callee,caller)使用方法

    在提到上述的概念之前,首先想说说javascript中函数的隐含参数: arguments arguments 该对象代表正在执行的函数和调用它的函数的参数.[function.]arguments[ ...

  6. 解决Ubuntu 下 vi编辑器不能使用方向键和退格键问题

    转自:http://blog.csdn.net/sky101010ws/article/details/51012103 使用vi命令时,不能正常编辑文件,使用方向键时老是出现很多字母 这个问题主要是 ...

  7. currentRowChanged 的注意事项

    Qt中的表单控件QListWidget类提供了许多信号函数,可以和用户交互,其中有个currentRowChanged ( int currentRow ) 是检测当前选中行是否发生了改变,如果改变了 ...

  8. (转)http接口测试——Jmeter接口测试实例讲解

    http://my.oschina.net/hellotest/blog/512482

  9. BI案例:某公司BI系统的九大主题分析

    1.KPI分析 KPI分析按照管理层次和时间纬度对指标进行汇总统计及分析展示,以适应各级领导的管理需求.在某公司,KPI不仅只是一个数据展示,而且已经成为一个内部考核指标的监控平台.各级领导每天上班的 ...

  10. 如何将MVC Areas中的某一个页设为起始页

    area的默认页: routes.MapRoute( name: "MyArea", url: "{controller}/{action}/{id}", de ...