J-基础-线程-等待唤醒机制
作者:互联网
线程状态:
1.新建(NEW):新建线程Thread,还未执行start()。
2.运行状态(Runnable):线程中的就绪(ready)和运行中(running)两种状态统称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3.阻塞(Blocked):表示线程阻塞于锁。
4.等待(Waiting):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5.超时等待(Timed Waiting):同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态 将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。
6.终止(Teminated):因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
线程通信:
多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。
如生产者消费者问题,读者写者问题,处理同一数据,但是需要开启两个不同的线程任务。连个任务同时处理同一数据,两个线程存在线程通信问题。
等待唤醒机制:
- wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时 的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象 上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中
- notify:则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先 入座。
- notifyAll:则释放所通知对象的 wait set 上的全部线程。
注:
哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而 此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调 用 wait 方法之后的地方恢复执行。
调用wait和notify方法需要注意的细节: - wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对 象调用的wait方法后的线程。
- wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继 承了Object类的。
- wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方 法。
代码:
包子铺线程生产包子,吃货线程消费包子。当包子没有时(包子状态为false),吃货线程等待,包子铺线程生产包子 (即包子状态为true),并通知吃货线程(解除吃货的等待状态),因为已经有包子了,那么包子铺线程进入等待状态。 接下来,吃货线程能否进一步执行则取决于锁的获取情况。如果吃货获取到锁,那么就执行吃包子动作,包子吃完(包 子状态为false),并通知包子铺线程(解除包子铺的等待状态),吃货线程进入等待。包子铺线程能否进一步执行则取 决于锁的获取情况。
代码:
main:
public class Main {
private Boolean BaoziHave = false;
public static void main(String[] args) {
BaoZi baoZi = new BaoZi();
Xiaofei xiaofei = new Xiaofei("消费者",baoZi);
Shengchan shengchan = new Shengchan("生产者",baoZi);
xiaofei.start();
shengchan.start();
}
}
BaoZi类:
public class BaoZi {
String pier ;
String xianer ;
boolean flag = false ;//包子资源 是否存在 包子资源状态
}
Xioafei类
public class Xiaofei extends Thread {
private BaoZi bz;
public Xiaofei(String name,BaoZi bz){
super(name); this.bz = bz;
}
@Override
public void run() {
while(true){
synchronized (bz){
if(bz.flag == false){//没包子
try {bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("吃货正在吃"+bz.pier+bz.xianer+"包子");
bz.flag = false;
bz.notify();
}
}
}
}
Shengchan类
public class Shengchan extends Thread{
private BaoZi bz;
public Shengchan(String name,BaoZi bz){
super(name); this.bz = bz;
}
@Override
public void run() {
int count = 0; //造包子
while(true){ //同步
synchronized (bz){
if(bz.flag == true){//包子资源 存在
try {bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 没有包子 造包子
System.out.println("包子铺开始做包子");
if(count%2 == 0){ // 冰皮 五仁
bz.pier = "冰皮";
bz.xianer = "五仁";
}else{// 薄皮 牛肉大葱
bz.pier = "薄皮";
bz.xianer = "牛肉大葱";
}
count++;
bz.flag=true;
System.out.println("包子造好了:"+bz.pier+bz.xianer);
System.out.println("吃货来吃吧"); //唤醒等待线程 (吃货)
bz.notify();
}
}
}
}
标签:等待,吃货,public,线程,唤醒,包子,bz,wait 来源: https://blog.csdn.net/qq_40811542/article/details/112989267