一:什么是等待唤醒机制
这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。
就是在一个线程进行了规定操作后,就进入等待状态( wait ),等待其他线程执行完他们的指定代码过后 再将其唤醒( notify));在有多个线程进行等待时,如果需要,可以使用 notifyAll0来唤醒所有的等待线程。
wait/notify 就是线程间的一种协作机制二:
等待唤醒中的方法
等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下
1.wait: 线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是”通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列 (ready queue)中
2.notify: 则选取所通知对象的 wait set 中的一个线程释放:例如,馆有空位置后,等候就最久的顾客最先入座。
3.notifyAll : 则释放所通知对象的 wait set 上的全部线程三:
调用wait和notify方法需要注意的细节
1.wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notiy唤醒使用同一个锁对象调用的wait方法后的线程。
2.wait方法与notifv方法是属于Obiect类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Obiect类的。
3.wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
生产者和消费者
首先要新建4个类。
生产线程的类(包子铺类)
消费线程的类(顾客的类)
包子类(作为线程安全的锁对象)同时调用等待唤醒方法也要用到这个类
消费品
public class BaoZi {
// 包子的名称
String name;
// 包子是否存在
boolean flag;
}
吃包子类
public class ChiHuo extends Thread{
//资源对象
BaoZi baoZi;
// 定义构造方法;给线程定义名字,同事给BaoZi对象赋值
public ChiHuo(String threadName,BaoZi bz){
super(threadName);
this.baoZi = bz;
}
//吃货线程的功能:
//如果包子不存在 线程进入等待状态
//如果包子存在 线程开始吃包子,吃完后更改包子的状态变为不存在,唤醒包子店线程开始制作 //包子
@Override
public void run(){
String threadName = Thread.currentThread().getName();
for(int i = 0 ; i<10;i++){
synchronized (baoZi){
// 包子存在
if(baoZi.flag){
// 吃包子
System.out.println(threadName+"正在吃"+baoZi.name);
// 更改包子状态
baoZi.flag=false;
// 唤醒同一资源下的其他线程
baoZi.notify();
}else{
try{
baoZi.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
}
做包子类以及测试类
public class ZaoCanDian extends Thread{
//资源对象
BaoZi baoZi;
//定义构造方法
public ZaoCanDian(String threadName,BaoZi bz){
super(threadName);
this.baoZi = bz;
}
//早餐店线程功能:
//如果包子存在 线程进入等待状态
//如果包子不存在 线程开始制作包子,制作完毕更改包子状态为存在,唤醒吃货线程吃包子
@Override
public void run(){
String threadName = Thread.currentThread().getName();
for(int i = 0 ; i< 10;i++){
synchronized (baoZi){
// 包子存在
if(baoZi.flag){
try{
baoZi.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}else{
System.out.println(threadName+"制作"+baoZi.name);
// 更改包子状态
baoZi.flag = true;
// 唤醒同一资源下的其它线程
baoZi.notify();
}
}
}
}
public static void main(String[] args) {
BaoZi bz = new BaoZi();
// 包子名称
bz.name="包子";
// 包子初始状态
bz.flag=false;
// 消费者名称
ChiHuo ch = new ChiHuo("猪八戒",bz);
// 生成者名称
ZaoCanDian zcd = new ZaoCanDian("春光早餐",bz);
// 启动线程
ch.start();
zcd.start();
}
}