等待唤醒机制
这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争( race ),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。
就是在一个线程进行了规定操作后,就进入等待状态 ( wait()),等待其他线程执行完他们的指定代码过后再将其唤醒( notify()) ;在有多个线程进行等待时,如果需要,可以使用notifyAll()来唤醒所有的等待线程。
wait / notify 就是线程间的一种协作机制。
一、等待唤醒中的方法
等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下︰
- wait :线程不再活动,不再参与调度,进入wait set中,因此不会浪费CPU资源,也不会去竞争锁了,这时的线程状态即是WAITING。它还要等着别的线程执行一个特别的动作,也即是"通知( notify ) "在这个对象上等待的线程从wait set中释放出来,重新进入到调度队列( ready queue )中
- notify :则选取所通知对象的wait set 中的一个线程释放﹔例如,餐馆有空位置后,等候就餐最久的顾客最先入座。
- notifyAll :则释放所通知对象的wait set 上的全部线程。
二、包子铺案例
1.代码如下
Baozi实体类代码如下(示例):
/**
* 功能描述:包子实体类
*
* @Author: wang
* @Date: 2022/4/29 22:32
*/
public class Baozi {
private String pi;
private String xian;
private boolean flag = false;// 判断有没有包子,默认没有:false
public Baozi(String pi, String xian, boolean flag) {
this.pi = pi;
this.xian = xian;
this.flag = flag;
}
public Baozi() {
}
public String getPi() {
return pi;
}
public void setPi(String pi) {
this.pi = pi;
}
public String getXian() {
return xian;
}
public void setXian(String xian) {
this.xian = xian;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
Bao_ZP线程类代码如下(示例):
import java.util.Date;
/**
* 功能描述:包子铺生产包子
*
* @Author: wang
* @Date: 2022/4/29 22:34
*/
public class Bao_ZP extends Thread {
private Baozi bz;
public Bao_ZP(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
synchronized (bz) {
int count=0;
while (true) {
if (bz.isFlag() == false) {
System.out.println("包子没货需要生产!!!");
try {
// 交替生产两种馅的包子。
if (count % 2 == 0) {
bz.setPi("白皮");
bz.setXian("绿馅");
} else {
bz.setPi("黑皮");
bz.setXian("红馅");
}
Date date = new Date();
System.out.println("包子铺正在生产" + bz.getPi() + bz.getXian() + "的包子,请稍等!");
System.out.println("...");
bz.wait(5000);/*假设生产包子需要五秒钟*/
System.out.println("包子铺" + bz.getPi() + bz.getXian() + "的包子,生产好了!");
bz.setFlag(true);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bz.notify();
}
} else {
try {
//有包子不需要生产,归还cpu进入等待状态
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Chi_bz线程类代码如下(示例):
/**
* 功能描述:顾客吃包子
*
* @Author: wang
* @Date: 2022/4/29 23:14
*/
public class Chi_bz extends Thread{
private Baozi bz;
public Chi_bz(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
synchronized (bz){
while (true){
if (bz.isFlag()==true){
System.out.println("顾客买到包子了,开始吃包子");
System.out.println("...");
try {
// 假设吃包子需要五秒钟。
bz.wait(5000);
System.out.println("包子吃完了");
// 更改包子状态,没有包子了:false
bz.setFlag(false);
System.out.println("**********************************************");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 释放线程。
bz.notify();
}
}else {
try {
// 没有包子,进入等待状态,等包子铺做。
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
TreadTest线程测试类代码如下(示例):
/**
* 功能描述:测试启动做包子线程和吃包子线程
*
* @Author: wang
* @Date: 2022/4/29 22:59
*/
public class TreadTest {
public static void main(String[] args) {
Baozi baozi = new Baozi();
Bao_ZP bao_zp = new Bao_ZP(baozi);
Chi_bz chi_bz = new Chi_bz(baozi);
chi_bz.start();
bao_zp.start();
}
}
2.运行结果
结果如下(示例):
包子没货需要生产!!!
包子铺正在生产白皮绿馅的包子,请稍等!
...
包子铺白皮绿馅的包子,生产好了!
顾客买到包子了,开始吃包子
...
包子吃完了
**********************************************
包子没货需要生产!!!
包子铺正在生产黑皮红馅的包子,请稍等!
...
包子铺黑皮红馅的包子,生产好了!
顾客买到包子了,开始吃包子
...
包子吃完了
**********************************************
注意:为了测试运行结果使用了while(true){}
设置为死循环。