设计模式:如何优雅地手写生产者消费者模式

生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。

在应用解耦、流量削峰等场景下常需要用到消息队列,生产者不断生产消息投递到队列里面,不必等待消费者消费;消费者从队列里面取消息进行处理,不需要找生产者要数据;这就是典型的生产者消费者模式,平衡了生产者消费者的处理能力,达到了解耦的目的。

当面试中被问“你了解那些设计模式”的时候,只回答一个单例模式未免显得有点不够专业,多了解一下效果可能会稍好一点。和单例模式对比,生产者消费者模式实现也比较简单,适合手写;对于其中的细节又可以再挖掘。

不多叨叨了,本文就自己实现一个阻塞队列,然后创建生产者和消费者,来实现一个简单的生产者消费者模式。

实现阻塞队列

  1. 生产者在队列未满时一直生产,满了则停止生产;
  2. 消费者在队列不为空的时候一直消费,空了则停止消费;
  3. 当消费者发现队列里面没有消息了通知生产者生产;
  4. 当生产者生产了消息通知消费者消费。
public class MyBlockingQueue {

    private int maxSize;
    private List<Long> queue;

    public MyBlockingQueue(int maxSize) {
        this.maxSize = maxSize;
        this.queue = new ArrayList<>();
    }

    public synchronized void put() {
        while (queue.size() == maxSize) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Long value = System.currentTimeMillis();
        queue.add(value);
        System.out.println("put:" + value);
        notify();
    }

    public synchronized void take() {
        while (queue.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Long value = queue.get(0);
        System.out.println("take:" + value);
        queue.remove(0);
        notify();

    }
}

实现生产者

public class Producer implements Runnable {

    private MyBlockingQueue queue;

    public Producer(MyBlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            queue.put();
        }
    }
}

实现消费者

public class Consumer implements Runnable {

    private MyBlockingQueue queue;

    public Consumer(MyBlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            queue.take();
        }
    }
}

实现生产者消费者模型

public class Main {
    public static void main(String[] args) throws InterruptedException {
        MyBlockingQueue queue = new MyBlockingQueue(100);
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);
        new Thread(producer).start();
        Thread.sleep(10);
        new Thread(consumer).start();
    }
}
posted @   James_Shangguan  阅读(1773)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
历史上的今天:
2018-11-24 PyCharm出现TabError: inconsistent use of tabs and spaces in indentation最简单实用的解决办法
2018-11-24 Python编程从入门到实践笔记——异常和存储数据
2018-11-24 Python编程从入门到实践笔记——文件
2018-11-24 Python编程从入门到实践笔记——类
2018-11-24 Python编程从入门到实践笔记——函数
2018-11-24 Python编程从入门到实践笔记——用户输入和while循环
2018-11-24 Python编程从入门到实践笔记——字典
点击右上角即可分享
微信分享提示