【从零开始学Java | 第四十二篇】生产者消费者问题(等待唤醒机制)

目录

前言

一、什么是"生产者-消费者"模型?

1.经典实现(wait()、notifyAll())

2.阻塞队列实现(BlockingQueue)

①阻塞队列的继承结构

总结


前言

之前学习多线程所执行的代码我们可以看到他们的执行都是随机的,哪个电影院窗口卖出一张门票是不固定的,但是如果我们想要让线程执行的顺序固定,应该如何操作呢?

一、什么是"生产者-消费者"模型?

为了方便理解,我们打个最通俗的比方:包子铺

  • 生产者**(Producer)**:后厨做包子的师傅。

  • 消费者**(Consumer)**:在前台买包子的顾客。

  • 缓冲区**(Buffer)**:装包子的蒸笼(容量有限,比如最多装 10 个)。

如果没有蒸笼,师傅做好一个包子,必须亲手交到顾客手里才能回去做下一个。如果顾客还没来,师傅就只能傻等着;反过来,如果师傅做得慢,顾客也得干等着。

1.经典实现(wait()、notifyAll())

桌子:定义了锁、消费者可以消费的总数、判断桌子上是否有包子。

java 复制代码
public class Desk {
    //锁
    public static Object obj = new Object();

    //总数
    public static int count = 10;

    //flag判空
    public static int flag = 0;

}

消费者线程:

java 复制代码
//消费者线程
public class Consumer extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (Desk.obj){
                if(Desk.count == 0){    //1.消费者吃饱了
                    break;
                } else {    //2.消费者没吃饱
                    if(Desk.flag == 0){     //2.1桌子上没食物
                        try {
                            Desk.obj.wait();        //2.1.1等待
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {        //2.2桌子上有食物
                        Desk.count--;   //2.2.1开吃
                        Desk.flag = 0;
                        System.out.println(getName() + "正在吃东西,还能再吃" + Desk.count + "份食物");
                        Desk.obj.notifyAll();   //2.2.2叫醒生产者.
                    }
                }
            }
        }
    }
}

生产者线程:

java 复制代码
//生产者线程
public class Productor extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (Desk.obj){
                if(Desk.count == 0){    //1.消费者吃饱了,就不用做了
                    break;
                } else {                //2.消费者没吃饱
                    if(Desk.flag == 1){     //2.1桌子上是有食物的
                        try {
                            Desk.obj.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else{                 //2.2桌子上没食物
                        Desk.flag = 1;              //2.2.1做食物
                        System.out.println(getName() + "正在做食物");
                        Desk.obj.notifyAll();
                    }
                }
            }
        }
    }
}

测试:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Consumer c = new Consumer();
        Productor p = new Productor();

        c.setName("消费者");
        p.setName("生产者");

        c.start();
        p.start();
    }
}

运行结果:

2.阻塞队列实现(BlockingQueue)

①阻塞队列的继承结构

接口:Itreable、Collection、Queue、BlockingQueue

实现类:

  • ArrayBlockingQueue:底层是数组,有界。
  • LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大为int的最大值。

消费者线程:

java 复制代码
public class Consumer extends Thread{
    ArrayBlockingQueue<String> queue;

    public Consumer(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while(true){
            try {
                String take = queue.take();

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

生产者线程:

java 复制代码
public class Productor extends Thread{
    ArrayBlockingQueue<String> queue;

    public Productor(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            queue.put("包子");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

测试:

java 复制代码
public class Test {
    public static void main(String[] args) {
        //定义阻塞队列
        ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<>(1);

        Consumer c = new Consumer(abq);
        Productor p = new Productor(abq);

        c.start();
        p.start();
    }
}

总结

生产者-消费者模型并不是一个具体的类,而是一种极具智慧的架构思想。

  1. 解耦:生产者和消费者彼此不直接打交道,只和缓冲区交互。

  2. 异步:大家各干各的,互不干扰。

  3. 缓冲:完美解决生产和消费速度不匹配的问题。

😁😁

相关推荐
铁皮哥11 小时前
【力扣题解】LeetCode 25. K 个一组翻转链表
java·数据结构·windows·python·算法·leetcode·链表
小新同学^O^11 小时前
简单学习 --> 单例模式
java·学习·多线程
Henray202411 小时前
LRU缓存设计与实现
java·面试
南宫萧幕12 小时前
基于 MATLAB 的插电混动汽车 CD-CS 策略 WLTC 前向仿真实现
开发语言·matlab·汽车
代钦塔拉12 小时前
第一篇:工业级 C++/Qt 项目头文件包含原则:告别循环依赖与编译玄学
开发语言·c++·qt
甲方大人请饶命12 小时前
SSM-基础
java·数据库·spring
谷雨不太卷12 小时前
Linux基础IO
java·开发语言
小新同学^O^12 小时前
简单学习 --> 文件IO
java·学习·文件io
神仙别闹12 小时前
基于PHP+MySQL实现在线考试系统
开发语言·mysql·php
吴声子夜歌12 小时前
Java——Arrays
java·算法·排序算法