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

😁😁

相关推荐
java1234_小锋4 分钟前
LangChain4j 开发Java Agent智能体- 整合SpringBoot4
java·开发语言·langchain4j
basketball6167 分钟前
C++进阶:3. unique_ptr 现代C++内存管理的基石
java·jvm·c++
我不是懒洋洋11 分钟前
从零实现一个Redis客户端:RESP协议与网络编程
开发语言·c++
zzqssliu13 分钟前
跨境代购系统的物流和通知模块重构思考:从设计模式到生产落地
java·设计模式·重构
小小码农Come on16 分钟前
Qt::WA_StyledBackground属性的作用
开发语言·qt
appearappear16 分钟前
一句sql 根据明细数据状态,精确更新一个主单主状态
java
许彰午19 分钟前
04_Java数组操作全解
java·开发语言·python
AIGS00120 分钟前
生产运营三大瓶颈,工业AI怎么破局?
java·人工智能·人工智能ai大模型应用
码不停蹄的玄黓20 分钟前
Java 线程池 execute() 和 submit() 对比
java·开发语言
方也_arkling28 分钟前
【Java-Day19】集合1(Collect单列集合)
java·开发语言