这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。
就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。
wait/notify 就是线程间的一种协作机制。
方法名 | 说明 |
---|---|
public final void wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 |
public final void notify() | 唤醒在此对象监视器上等待的单个线程。 |
public final void notifyAll() | 唤醒在此对象监视器上等待的所有线程。 |
1、wait方法与notify方法必须要由同一个锁对象调用因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
2、wait方法与notify方法是属于Object类的方法的因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
3、wait方法与notify方法必须要在同步代码块或者是同步函数中使用因为:必须要通过锁对象调用这2个方法。
等待唤醒机制其实就是经典的“生产者与消费者”的问题。
这里定义一个生产者生产包子,消费者吃包子的案例,生产者线程生产包子,消费者线程消费包子。当包子没有时(包子状态为false),生产者线程等待,生产者线程生产包子(即包子状态为true),并通知消费者线程(解除消费者的等待状态),因为已经有包子了,那么生产者线程进入等待状态。接下来,消费者线程能否进一步执行则取决于锁的获取情况。如果消费者获取到锁,那么就执行吃包子动作,包子吃完(包子状态为false),并通知生产者线程(解除生产者的等待状态),消费者线程进入等待。生产者线程能否进一步执行则取决于锁的获取情况。
包子资源类
public class BaoZi {
private String skin;//包子皮
private String stuffing;//包子馅
boolean flag=false;//包子资源是否存在 这里默认给定是没有
public String getSkin() {
return skin;
}
public void setSkin(String skin) {
this.skin = skin;
}
public String getStuffing() {
return stuffing;
}
public void setStuffing(String stuffing) {
this.stuffing = stuffing;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
消费者类
public class Consumer extends Thread {
private BaoZi bz;
public Consumer(String name, BaoZi bz) {
//super调用父类Thread的构造方法 赋值name
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("消费者开始吃包子");
//包子吃完后把资源设为false
bz.setFlag(false);
//唤醒生产者进行成产包子
bz.notify();
}
}
}
}
生产者类
public class Producer extends Thread{
private BaoZi bz;
private int count=0;
public Producer(String name,BaoZi bz) {
//super调用父类Thread的构造方法 赋值name
super(name);
this.bz = bz;
}
@Override
public void run() {
while (true){
synchronized (bz){
//判断包子资源是否存在
if(bz.flag==true){
try {
bz.wait();//如果包子存在,则生产者进入等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//通过奇偶数来制作不同的包子,利于区分
if(count%2==0){
bz.setSkin("白面皮");
bz.setStuffing("猪肉大葱馅");
System.out.println("生产者开始生产包子");
System.out.println("生产了"+bz.getSkin()+bz.getStuffing()+"包子");
count++;
}else if(count%2==1){
bz.setSkin("荞麦面");
bz.setStuffing("胡萝卜粉条馅");
System.out.println("生产者开始生产包子");
System.out.println("生产了"+bz.getSkin()+bz.getStuffing()+"包子");
count++;
}
//把包子资源设为true
bz.setFlag(true);
//唤醒消费者去吃包子
System.out.println("生产者可以来吃包子啦");
bz.notify();
}
}
}
}
测试类
public class Test {
public static void main(String[] args) {
//定义一个包子对象,这个也是生产者和消费者共同的锁
BaoZi bz=new BaoZi();
//创建消费者和生产者对象,传递参数
Consumer c=new Consumer("消费者",bz);
Producer p=new Producer("生产者",bz);
c.start();
p.start();
}
}
因为默认给定包子的flag为false,所以在创建生产者对象时,检测到flag为false,所以生产者开始生产包子,而消费者进行等待,当生产者生产出包子后,进行等待,消费者被唤醒,开始吃包子。