Java的线程间通信,其实就是利用等待和唤醒机制达到多个线程之间协调工作的目的。
1. 等待和唤醒
Object类中有两个方法,wait()和notify()。这两个方法时在多线程中被锁对象调用的。因为所对象可以是任意对象,为了让任意对象都能调用这两个方法,所以把这两个方法设计到了Object方法中
void wait()
让当先正在执行的线程进入无限等待状态
void notify()
唤醒正在等待的线程
很经典的一个例子,就是生产者和消费者的案例。假设包子铺生产一个包子,吃货就要吃一个包子。用两个线程分别表示包子铺和吃货 ,包子铺线程生产一个包子,吃货线程就吃一个包子。
2. 案例分析
包子铺 和 吃货的共性数据就是包子。可以把包子当做锁对象。当两个线程共用一把锁的时候,就可以让两个线程达到互斥的效果(ps: 所谓互斥就是我执行你不执行;你执行我不执行)。
3. 代码实现
先写一个包子类
public class BaoZi {
private String pi; //包子皮
private String xian; //包子馅
private boolean flag;//包子状态 true表示有包子,false表示包子被吃了
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;
}
}
Copy
再写一个包子铺线程
public class BaoZiPu implements Runnable{
private BaoZi bz;
//通过构造方法给BaoZi对象赋值
public BaoZiPu(BaoZi bz){
this.bz=bz;
}
public void run(){
while(true){
synchronized (bz){
//如果有包子,包子铺等待
if(bz.isFlag()){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果等待结束了,就生产包子
System.out.println("包子铺生产了一个"+bz.getPi()+"..."+bz.getXian()+"的包子");
//生产好了包子把包子状态太为true
bz.setFlag(true);
bz.notify();//把等待的吃货线程唤醒
}
}
}
}
再写一个吃货线程
public class ChiHuo implements Runnable{
private BaoZi bz;
//通过构造方法给BaoZi对象赋值
public ChiHuo(BaoZi bz){
this.bz=bz;
}
public void run(){
while(true){
synchronized (bz){
//如果没有包子,吃货等待
if(!bz.isFlag()){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果吃货等待结束了,就吃包子
System.out.println("吃货吃了一个"+bz.getPi()+"..."+bz.getXian()+"的包子");
//吃货吃完包子把包子状态太为false
bz.setFlag(false);
bz.notify();//把等待的包子铺线程唤醒
}
}
}
}
再写测试类
public class Test{
public static void main(String[] args){
Baozi bz=new Baozi();
bz.setPi("冰皮");
bz.setXian("牛肉馅");
//创建包子铺线程,开启
new Thread(new BaoZiPu(bz)).start();
//创建吃货线程,开启
new Thread(new ChiHuo(bz)).start();
}
}