线程状态概述
等待唤醒案例分析
等待唤醒案例代码实现
package demo05;
/*
等待唤醒案例:线程之间的通信
创建一个顾客线程(消费者):告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入到WAITINg状态(无限等待)
创建一个老板线程(生产者):花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子
注意:
顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个执行
同步使用锁对象必须保证唯一
只有锁对象才能调用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() {
@Override
public void run() {
//一直等着买包子
while(true) {
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITINg状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,开吃!");
System.out.println("--------------------------------------------------");
}
}
}
}.start();
//创建一个老板线程(生产者)
new Thread() {
@Override
public void run() {
//一直做包子
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//花五秒做包子
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子");
//做好包子之后,调用notify方法,唤醒顾客吃包子
obj.notify();
}
}
};
}.start();
}
}
Object类中wait带参方法和notify
package demo05;
/*
进入到TimeWaiting(计时等待)有两种方式
1、使用sleep(long m)方法,在毫秒值结束之后,线程唤醒进入到Runnable/Block阻塞状态
2、使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,
线程睡醒进入到Runnable/Blocked状态
唤醒的方法():
void notify() 唤醒在此对象监视器上等待的单个线程
void notifyAll() 唤醒在此对象监视器上等待的所有线程
*/
public class Demo02WaitAndNotify {
public static void main(String[] args) {
//创建锁对象,保证唯一
Object obj = new Object();
//创建一个顾客线程(消费者)
new Thread() {
@Override
public void run() {
//一直等着买包子
while(true) {
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("顾客1告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITINg状态(无限等待)
try {
obj.wait(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,顾客1开吃!");
System.out.println("--------------------------------------------------");
}
}
}
}.start();
//创建一个顾客线程(消费者)
new Thread() {
@Override
public void run() {
//一直等着买包子
while(true) {
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("顾客2告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITINg状态(无限等待)
try {
obj.wait(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,顾客2开吃!");
System.out.println("--------------------------------------------------");
}
}
}
}.start();
//创建一个老板线程(生产者)
new Thread() {
@Override
public void run() {
//一直做包子
while(true) {
try {
//花5秒钟做包子
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//花五秒做包子
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子");
//做好包子之后,调用notify方法,唤醒顾客吃包子
//obj.notify();//如果有多个等待线程,随机唤醒一个
obj.notify();//唤醒所有等待的线程
}
}
};
}.start();
}
}
线程间通信
等待唤醒机制概述
等待唤醒机制需求分析
等待唤醒机制代码实现
package demo04;
/*
资源类:包子类
设置包子的属性
皮
馅
包子的状态:有true,没有false
*/
public class BaoZi {
//皮
String pi;
//馅
String xian;
//包子的状态:有true,没有false,设置初始值为false没有包子
boolean flag = false;
}
package demo04;
/*
生产者(包子铺)类:是一个线程类,可以继承Thread
设置线程任务(run):生产包子
对包子的状态进行判断
true:有包子
包子铺调用wait方法进入等待状态
false:没有包子
包子铺生产包子
增加一些趣味性:交替生产两种包子
有两种状态(i%2 == 0)
包子铺生产好了包子
修改包子的状态为true
唤醒吃货线程,让吃货线程吃包子
注意:
包子铺线程和包子线程关系-->通信(互斥)
必须同时同步技术保证两个线程只能有一个在执行
锁对象必须保证唯一,可以使用包子对象作为锁对象
包子铺类和吃货的类就需要把包子对象作为参数传递进来
1、需要在成员位置创建一个包子变量
2、使用带参数构造方法,为这个包子变量赋值
*/
public class BaoZiPu extends Thread{
//1、需要在成员位置创建一个包子变量
private BaoZi bz;
//2、使用带参数构造方法,为这个包子变量赋值
public BaoZiPu(BaoZi bz) {
this.bz = bz;
}
//设置线程任务(run):生产包子
public void run() {
//定义一个变量
int count = 0;
//让包子铺一直生产包子
while(true) {
//必须同时同步技术保证两个线程只能有一个在执行
synchronized (bz) {
//对包子的状态进行判断
if(bz.flag == true) {
//包子铺调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//被唤醒之后执行,包子铺生产包子
//增加一些趣味性:交替生产两种包子
if(count%2 == 0) {
//生产 薄皮儿三鲜馅、包子
bz.pi = "薄皮";
bz.xian = "三鲜馅";
} else {
//生产 冰皮 牛肉大葱馅
bz.pi = "冰皮";
bz.xian = "牛肉大葱馅";
}
count++;
System.out.println("包子铺正在生产:"+bz.pi+bz.xian+"包子");
//生产包子需要三秒钟
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//包子铺生产好了包子,修改包子的状态为true有
bz.flag = true;
//唤醒吃货线程,让吃货线程吃包子
bz.notify();
System.out.println("包子铺已经生产好了:"+bz.pi+bz.xian+"包子,吃货可以开始吃了");
}
}
}
}
等待唤醒机制代码实现 吃货类 测试
package demo04;
/*
测试类:
包含main方法,程序执行的入口,启动程序
创建包子对象
创建包子铺线程,开启,生产包子
创建吃货线程,开启,吃包子
*/
public class Demo {
public static void main(String[] args) {
//创建包子对象
BaoZi bz = new BaoZi();
//创建包子铺线程,开启生产包子
new BaoZiPu(bz).start();
//创建吃货线程,开启吃包子
new ChiHuo(bz).start();
}
}
package demo04;
/*
消费者(吃货类):是一个线程类,可以继承Thread
设置线程任务(run):吃包子
对包子的状态进行判断
false:没有包子
吃货调用wait方法进入等待状态
true:有包子
吃货吃包子
吃货吃完包子
修改包子的状态为false没有
吃货唤醒包子铺线程,生产包子
*/
public class ChiHuo extends Thread {
//1、需要在成员位置创建一个包子变量
private BaoZi bz;
//2、使用带参数构造方法,为这个包子变量赋值
public ChiHuo(BaoZi bz) {
this.bz = bz;
}
//设置线程任务(run);吃包子
@Override
public void run() {
//使用死循环,让吃货一直吃包子
while(true) {
//必须同时同步技术保证两个线程只能有一个在执行
synchronized (bz) {
//对包子的状态进行判断
if(bz.flag == false) {
//吃货调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//被唤醒之后执行的代码,吃包子
System.out.println("吃货正在吃:"+bz.pi+bz.xian+"的包子");
//吃货吃完包子
//修改包子的状态为false没有
bz.flag = false;
//吃货唤醒包子铺线程,生产包子
bz.notify();
System.out.println("吃货已经把:"+bz.pi+bz.xian+"的包子吃完了,包子铺开始生产包子");
System.out.println("--------------------------------------");
}
}
}
}
}