wait():————————让线程处于冻结状态,释放CPU的执行权和执行资格,将线程暂时存储到线程池中
API中的解释:
导致当前线程等待,直到另一个线程调用该对象的notify()
方法或notifyAll()
方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0)
。
当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify
方法或notifyAll
方法notifyAll
。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行
notify():会唤醒线程池中任意一个线程
API中的解释:
-
-
-
唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。 选择是任意的,并且由实施的判断发生。 线程通过调用public final void notify()
wait
方法之一等待对象的监视器。唤醒的线程将无法继续,直到当前线程放弃此对象上的锁定为止。 唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争在该对象上进行同步; 例如,唤醒的线程在下一个锁定该对象的线程中没有可靠的权限或缺点。
-
-
notifyall():会唤醒线程池中的所有线程
- 一个锁对应一个线程池子,锁是同步中对应的锁。
这几个方法必须使用在同步中,因为必须要标识,wait() notify() 等方法所属的锁,同一个锁上的notify() 只能唤醒该锁上被wait() 的线程。
解决一个小问题:在查找API文档时,这几个方法不在Thread 类中,而在Object 类中,这是因为:调用这几个方法一定要标识的锁(其实就是用一个对象去调用的形式,),任意对象都能调用的方法必定是Object 类中的方法。
———————————等待唤醒机制应用/多线程之间的通信—————————————
根据生产者消费者的例子:进行多生产多消费的多线程间的通信联系(问题分析很重要)
1. 增加线程——————导致线程安全问题。生产了商品没有被消费或者是一个商品被多次消费
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();
问题分析:(根据消费者 生产者代码)
t1 完整执行代码更改标记(商品1),唤醒t2(其实是唤醒 t2 t3 t4 中的任意一个),假设此时CPU没有切换,t1 继续执行,判断标记时t1 停止,t2 判断标记后也停止,假设接下来(1)t3 执行,t3 的二次执行时停止,t4 也停止了唤醒了t1 ,产生了商品2,改变标记,此时唤醒了t2 ,t2不用在判断标记,直接执行后面的代码,生产商品3,此时数据就会出现问题,商品2 虽被生产出来但是却没有被消费————产生安全问题
仔细分析产生问题的原因:线程没有判断标记————解决办法,将if 换成 while。记住在多线程通信中,都使用 while。
2.修改代码后会发现另一个问题:会出现死锁(所有线程都停住)
问题分析:就上段分析更改代码后,此时唤醒t2 ,t2 反复判断标记,flag==true; 此时所有的 线程都停止。出现死锁。
解决办法:
首先的思路是不唤醒同一方的线程(消费者就属于同一方),但是没有这样的解决代码
因此在唤醒时,就唤醒所有的线程,就算出现上述 : t1 唤醒t2 这种时候,此时t1 唤醒了所有线程,执行权在t2 时 t2 会停止,但是此时活着的线程还有t3 t4.执行权会切换,就不会出现死锁现象。
不唤醒同一方的线程(消费者就属于同一方)这个在JDK1.5及其以上的版本中是有解决办法的(见下一章笔记)
//注意,开始时:线程池中没有等待的线程,notify() 其实就是空叫醒
还有当一个线程执行完一次完整代码时,他任然有可能继续拥有执行权,这条线程继续执行
代码:
class Resource{//简化程序-设资源只有一个//多线程之间的通信
private String name;
private int number=1;
private boolean flag;
//提供设置方法
public synchronized void set(String name ){
while(flag){//先判断
try{wait();}catch(InterruptedException e){}//存在商品,此线程停止
}
//给成员变量赋值
this.name = name + number;
number++;
//打印生产了那个商品
System.out.println(Thread.currentThread().getName() + " 生产者 " + this.name);
flag = true;//生产完,修改标志
notifyAll() ;//唤醒消费者
}
//消费者的
public synchronized void Out(){
while(!flag){//先判断
try{wait();}catch(InterruptedException e){} //没有商品,消费者停止
}
System.out.println(Thread.currentThread().getName()+" 消费者 "+this.name);
flag =false;//修改标记
notifyAll();//唤醒生产者
}
}
//描述生产者
class Producer implements Runnable{
private Resource r;
Producer(Resource r){
this.r = r;
}
public void run(){
for(int x=0;x<5;x++) {
r.set("面包");
}
}
}
//描述消费者
class consumer implements Runnable{
private Resource r;
consumer(Resource r){
this.r=r;
}
public void run(){
for(int x=0;x<5;x++) {
r.Out();
}
}
}
public class producerAndConsumer {
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(con);
t1.start();
t2.start();
}
}