1、线程状态概述
![](https://img.haomeiwen.com/i7116577/4c3891212e906ee9.png)
2、等待唤醒案例分析
Timed waiting 计时等待
![](https://img.haomeiwen.com/i7116577/836ca8b616777c49.png)
blocked 阻塞
![](https://img.haomeiwen.com/i7116577/d6a04af360d94c1c.png)
waiting
![](https://img.haomeiwen.com/i7116577/10b79a47eda318cc.png)
3、等待唤醒案例代码实现
package exception2.waitandnotify;
/**
* created by apple on 2020/6/27
* 等待唤醒案例:线程之间的通信
* 创建一个顾客线程,消费者,告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
* 创建一个老板线程,生产者,花了5s做包子,做好包子之后,调用notify方法,唤醒顾客,吃包子。
注意事项:
1、顾客和老板线程,使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
2、同步使用的锁对象,保证唯一
3、只有锁对象,才能调用wait和notify方法,
*Object类中的方法:
* void wait(),在其他线程调用此对象的notify()或notifyAll()方法前,导致当前线程等待
* void notify(),唤醒在此对象监视器上等待的单个线程,会继续执行wait()方法之后的代码
*
*/
public class demo01waitandnotify {
public static void main(String[] args) {
//创建锁对象,保证唯一
Object obj = new Object();
//创建一个顾客线程
//匿名内部类
new Thread(){
//重写run方法,
@Override
public void run() {
//保证等待和唤醒的线程只有一个在执行,需要使用同步机制
synchronized (obj){
System.out.println("告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好,开吃");
}
}
}.start();
//创建老板线程,
new Thread(){
@Override
public void run() {
//花了5s做包子
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒的线程只有一个在执行,需要使用同步机制
synchronized (obj){
System.out.println("老板5s之后做好包子,告知顾客,可以吃包子");
//,调用notify方法,唤醒顾客,吃包子。
obj.notify();
}
}
}.start();
}
}
4、Object类中wait带参方法和notify方法
-
进入TimeWaiting(计时等待), 两种方式
1、使用sleep(Long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2、使用wait(Long m)方法,如果在毫秒值结束之后,还没有被notify唤醒,会自动醒来,线程睡醒进入Runnable/Blocked状态 -
唤醒的方法:
void()notify():唤醒在此对象监视器上等待的单个线程
void()notifyall() :所有线程
package exception2.waitandnotify;
/**
* created by apple on 2020/6/27
*/
public class Demo02waitAndNotify {
public static void main(String[] args) {
//创建锁对象,保证唯一
Object obj = new Object();
//创建一个顾客线程
//匿名内部类
new Thread(){
//重写run方法,
@Override
public void run() {
//保证等待和唤醒的线程只有一个在执行,需要使用同步机制
synchronized (obj){
System.out.println("顾客一告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
try {
obj.wait(5000); //没人叫醒,自己醒了。
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好,顾客一开吃");
}
}
}.start();
//创建一个顾客线程
//匿名内部类
new Thread(){
//重写run方法,
@Override
public void run() {
//保证等待和唤醒的线程只有一个在执行,需要使用同步机制
synchronized (obj){
System.out.println("顾客二告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
try {
obj.wait(5000); //没人叫醒,自己醒了。
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好,顾客二开吃");
}
}
}.start();
//创建老板线程,
new Thread(){
@Override
public void run() {
//花了5s做包子
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒的线程只有一个在执行,需要使用同步机制
synchronized (obj){
System.out.println("老板5s之后做好包子,告知顾客,可以吃包子");
// obj.notify(); 如果有多个等待线程,随机唤醒一个
//,调用notify方法,唤醒顾客,吃包子。唤醒所有等待线程,
obj.notifyAll(); //
}
}
}.start();
}
}
5、线程间通信
5.1 概念:多个线程在处理同一个资源,但处理的动作(线程的任务)不同。
比如:生产包子。吃包子
5.2 为什么要处理线程间通信
多个线程并发执行时 ,默认情况CPU 随机切换线程,当需要多个线程共同完成一件任务, 并且希望有规律的执行,那多线程之间需要一些通信,以达到多线程共同操作一份数据
方式: 等待唤醒机制
6、 等待唤醒机制概述
多个线程间协作机制
![](https://img.haomeiwen.com/i7116577/cc5d58084a07a5b5.png)
重点:有效利用资源
7、 等待唤醒机制需求分析
![](https://img.haomeiwen.com/i7116577/53ddbd3c1a645d1d.png)
8、 等待唤醒机制代码实现——包子类& 包子铺
根据上面的图,创建包子类
package con.day13.demo05.Thread.ThreadWait;
public class BaoZi {
/*
资源类:包子类
属性 皮,馅, 状态
*/
String pi;
String xian;
boolean flag = false;
}
包子铺
package con.day13.demo05.Thread.ThreadWait;
import jdk.nashorn.internal.ir.CallNode;
public class BaoZiPu extends Thread{
/*
生成者。
注意:
1、包子铺和包子的关系通信关系,互斥关系,必须使用同步技术,保证两个线程只有一个在执行
2、锁对象保证唯一, 可以使用包子对象作为锁对象
3、包子铺类和吃货类就需要把包子对象作为参数传递过来,
1、需要在成员位置创建一个包子变量
2、使用带参数构造方法,为包子变量赋值
*/
//1、需要在成员位置创建一个包子变量
private BaoZi bz;
//2、使用带参数构造方法,为包子变量赋值
public BaoZiPu (BaoZi bz) {
this.bz = bz;
}
@Override
public void run() {
//定义一个变量
int count = 0;
//让包子铺一直生产包子
while (true){
//必须同步技术保证两个线程只能有一个在执行
synchronized (bz){
//对包子的状态进行判断
if (bz.flag == true){
//有包子,包子铺调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没有包子,包子铺生成包子,增加趣味性,交替生成两种包子
if (count %2 == 0){
//生产薄皮 三鲜包子
bz.pi = "薄皮";
bz.xian = "三鲜";
}else{
//生产厚皮,牛肉馅包子
bz.pi = "厚皮";
bz.xian = "牛肉馅";
}
count++;
System.out.println("包子铺正在生产" + bz.pi+ bz.xian + "的包子");
//生产需要3s
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//生产完包子。修改包子状态为true
bz.flag = true;
//唤醒吃货线程
bz.notify();
System.out.println("包子铺已经生产好了" + bz.pi + bz.xian + "可以开始吃了");
}
}
}
}
9、 等待唤醒机制代码实现——吃货类&测试
根据上面的图,创建吃货类,
package con.day13.demo05.Thread.ThreadWait;
public class Chihuo extends Thread{
//1、需要在成员位置创建一个包子变量
private BaoZi bz;
//2、使用带参数构造方法,为包子变量赋值
public Chihuo (BaoZi bz) {
this.bz = bz;
}
//设置线程任务,吃包子
@Override
public void run() {
//使用死循环,让吃货一直吃包子
while (true){
synchronized (bz){
//对包子状态进行判断
if (bz.flag = false){
//没包子,吃货调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//被唤醒后,执行代码,吃包子
System.out.println("吃货吃" + bz.pi + bz.xian + "包子");
//吃货吃完,修改状态
bz.flag = false;
//吃货唤醒包子铺线程,
bz.notify();
System.out.println("吃货已经把" + bz.pi + bz.xian + "包子吃完了");
}
}
}
}
}
测试类:
package con.day13.demo05.Thread.ThreadWait;
public class DemoC {
public static void main(String[] args) {
//创建包子对象
BaoZi bz = new BaoZi();
//创建包子铺线程,开始生产包子
new BaoZiPu(bz).start();
//创建吃货线程,开始吃包子
new Chihuo(bz).start();
}
}
网友评论