前言
- 生产者和消费者模式是一个十分经典的多线程协作模式,该模式又称为等待唤醒机制。
- 本质上就是打破多线程的随机性,使得线程轮流执行。
问题分析
生产者和消费者问题:
- 生产者生产数据,消费者消费数据,需要借助第三方控制线程的执行。
- 理想情况:生产者生产一个数据,消费者消费一个数据。
- 消费者等待:消费者先抢到cpu执行权,wait数据,生产者生产完数据后notify消费者。
- 生产者等待:如果生产者再次抢到cpu执行权,而数据已经存在,则wait。
案例分析
生产者和消费者(常见方法)
方法名称 | 说明 |
void wait() | 当前线程等待,直到被其他线程唤醒 |
void notify() | 随机唤醒单个线程 |
void notifyAll() | 唤醒所有线程 |
java里规定了每一个锁都对应了一个等待队列,唤醒的是锁上等待队列的线程。
案例模型
案例源码
Desk
public class Desk {/*作用:控制消费者和生产者的执行*///是否有面条 0:没有面条 1:有面条public static int foodFlag =0;//总个数public static int count =10;//锁对象public static Object lock = new Object();
}
Foodie
public class Foodie extends Thread{@Overridepublic void run() {/*1.循环2.同步代码块3.判断共享数据是否到了末尾(到了末尾)3.判断共享数据是否到了末尾(没有,执行核心代码块)*/while (true){synchronized (Desk.lock){if (Desk.count==0){break;}else{//判断是否有面条if (Desk.foodFlag==0){//如果没有,就等待try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else {//把吃的总数-1Desk.count--;//如果有,就开吃System.out.println("吃货在吃面条,还能吃"+Desk.count+"碗!!");//吃完后唤醒厨师继续Desk.lock.notifyAll();//修改桌子状态Desk.foodFlag=0;}}}}}
}
Cook
public class Cook extends Thread {@Overridepublic void run() {/*1.循环2.同步代码块3.判断共享数据是否到了末尾(到了末尾)3.判断共享数据是否到了末尾(没有,执行核心代码块)*/while (true){synchronized (Desk.lock){if (Desk.count==0){break;}else {//判断桌子上是否有食物if(Desk.foodFlag==1){//如果有,就等待try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else{//如果没有,就制作食物System.out.println("厨师做了一碗面条");//修改桌子上的食物状态Desk.foodFlag=1;//叫醒等待的消费者开吃Desk.lock.notifyAll();}}}}}
}
Demo
public class ThreadDemo {public static void main(String[] args) {/*需求:完成生产者和消费者(等待唤醒机制代码)、实现线程轮流执行的效果*///创建线程对象Cook c=new Cook();Foodie f = new Foodie();//给线程设置名字c.setName("厨师");f.setName("吃货");//开启线程c.start();f.start();}
}
总结
一个等待唤醒机制的多线程协作模型,往往需要借助第三方来控制线程的执行流程。