【从零开始学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. 缓冲:完美解决生产和消费速度不匹配的问题。

😁😁

相关推荐
流年如夢1 小时前
自定义类型进阶:联合与枚举
java·c语言·开发语言·数据结构·数据库·c++·算法
Little At Air2 小时前
C++stack模拟实现
linux·开发语言·c++·算法
霸道流氓气质2 小时前
SpringBoot+LangChain4j+Ollama实现Function Calling工具调用-仿智能客服示例
java·spring boot·后端
Ulyanov2 小时前
《玩转QT Designer Studio:从设计到实战》 QT Designer Studio组件化开发与UI组件库构建
开发语言·python·qt·ui·雷达电子战系统仿真
词元Max2 小时前
2.8 pydantic 数据校验:AI 开发的隐形利器
开发语言·人工智能·python
2401_865382502 小时前
各省政务信息化项目验收材料清单汇总及差异分析
java·开发语言·数据库
froginwe112 小时前
MySQL 删除数据库
开发语言
Rust研习社2 小时前
深入浅出 Rust 泛型:从入门到实战
开发语言·后端·算法·rust
京师20万禁军教头2 小时前
31面向对象(中级)-方法重写/覆盖(override)
java