Java学习日志(十二): 线程状态,等待与唤醒案例
程序员文章站
2022-05-04 17:53:24
...
JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)
Java学习日志(十二)
线程状态
在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态:
线程状态 | 导致状态发生条件 |
---|---|
NEW(新建) | 线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) | 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。 |
Blocked(锁阻塞) | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
Waiting(无限等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
Timed Waiting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。 |
Teminated(被 终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。 |
等待与唤醒案例(包子铺案例)
等待与唤醒:线程之间的通信
Object类中的方法
-
void wait()
导致当前线程等待它被唤醒,通常是通知或中断 。 -
void notify()
唤醒正在此对象监视器(对象锁)上等待的单个线程。
注意:
- wait和notify方法必须由锁对象调用(必须是同个锁对象)
锁对象–>wait() 锁对象–>notify() - wait和notify方法一般写在同步中
案例:包子铺案例
需求:
两大线程:设线程A(包子铺),执行生产包子的动作。线程B(吃货),执行吃包子的操作
共享资源:包子
执行动作:生产一个包子,吃一个包子
分析:
对包子的状态进行分析
没有包子:吃货线程唤醒包子铺线程—>吃货线程等待—>包子铺线程做包子—>包子铺做好包子—>修改包子的状态—>有包子
有包子:包子铺唤醒吃货线程—>包子铺线程等待—>吃货吃包子—>修改包子的状态—>没有包子
…(循环)
代码实现:
资源类:包子,其中有皮,陷,包子的状态
public class BaoZi {
String pi;
String xian;
//包子状态,初始值为false,没有包子
boolean flag = false;
}
包子铺类:是一个线程类,线程任务:生产包子
对包子的状态进行判断:
true:有包子
包子铺线程调用wait等待
false:没有包子
包子铺线程生产包子
生产x皮x陷的包子
生产包子花费3秒
生产完包子,修改包子状态为true
包子铺线程唤醒吃货线程,吃包子
注意:
- 生产包子和吃包子,只能有一个在执行,需要使用同步技术
- 同步技术需要使用锁对象,可以使用包子对象
在成员位置创建一个包子对象
使用构造方法为包子变量赋值
public class BaoZiPu implements Runnable {
//在成员位置创建一个包子对象
BaoZi bz;
//使用构造方法为包子变量赋值
public BaoZiPu(BaoZi bz) {
this.bz = bz;
}
//线程任务:生产包子
@Override
public void run() {
while(true){
/*
1.生产包子和吃包子,只能有一个在执行,需要使用同步技术
2.同步技术需要使用锁对象,可以使用包子对象
*/
synchronized (bz){
//对包子状态进行判断
if(bz.flag==true){
//true:有包子
// 包子铺线程调用wait等待
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//包子铺被吃货唤醒之后执行的代码
//false:没有包子,包子铺线程生产包子
//生产x皮x陷的包子
bz.pi = "薄皮";
bz.xian = "玉米鲜肉";
System.out.println("包子铺正在生产"+bz.pi+bz.xian+"的包子!");
//生产包子花费3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//生产完包子,修改包子状态为true
bz.flag = true;
//包子铺线程唤醒吃货线程,吃包子
bz.notify();
System.out.println("包子铺已经生产好"+bz.pi+bz.xian+"的包子!");
}
}
}
}
吃货类:是一个线程类,线程任务:吃包子
对包子的状态进行判断:
false:没有包子
吃货线程调用wait等待
true:有包子
吃货线程开始吃包子
打印吃x皮x陷的包子
吃完包子,修改包子的状态为false
吃货线程唤醒包子铺线程,做包子
注意:
- 生产包子和吃包子,只能有一个在执行,需要使用同步技术
- 同步技术需要使用锁对象,可以使用包子对象
在成员位置创建一个包子对象
使用构造方法为包子变量赋值
public class ChiHuo implements Runnable{
//在成员位置创建一个包子对象
BaoZi bz;
//使用构造方法为包子变量赋值
public ChiHuo(BaoZi bz) {
this.bz = bz;
}
//线程任务:吃包子
@Override
public void run() {
while (true){
/*
1.生产包子和吃包子,只能有一个在执行,需要使用同步技术
2.同步技术需要使用锁对象,可以使用包子对象
*/
synchronized (bz){
//对包子的状态进行判断
// false:没有包子
if (bz.flag==false){
//吃货线程调用wait等待
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
吃货线程被包子铺线程唤醒之后执行的代码
*/
//true:有包子,吃货线程开始吃包子
//打印吃x皮x陷的包子
System.out.println("吃货正在吃"+bz.pi+bz.xian+"的包子!");
//吃完包子,修改包子的状态为false
bz.flag = false;
//吃货线程唤醒包子铺线程,做包子
bz.notify();
System.out.println("吃货已经吃完了"+bz.pi+bz.xian+"的包子!包子铺赶紧生产包子!");
System.out.println("-----------------------");
}
}
}
}
测试类:
创建一个包子对象
创建一个包子铺线程,生产包子
创建一个吃货线程,吃包子
public class Demo01 {
public static void main(String[] args) {
//创建一个包子对象
BaoZi bz = new BaoZi();
//创建一个包子铺线程,生产包子
new Thread(new BaoZiPu(bz)).start();
//创建一个吃货线程,吃包子
new Thread(new ChiHuo(bz)).start();
}
}
运行结果:
包子铺正在生产薄皮玉米鲜肉的包子!
包子铺已经生产好薄皮玉米鲜肉的包子!
吃货正在吃薄皮玉米鲜肉的包子!
吃货已经吃完了薄皮玉米鲜肉的包子!包子铺赶紧生产包子!
-----------------------
包子铺正在生产薄皮玉米鲜肉的包子!
包子铺已经生产好薄皮玉米鲜肉的包子!
吃货正在吃薄皮玉米鲜肉的包子!
吃货已经吃完了薄皮玉米鲜肉的包子!包子铺赶紧生产包子!
-----------------------
...
上一篇: 线程池的四种阻塞队列与四种任务拒绝策略
下一篇: 【JAVA】线程池