设计模式 Concurrency 之 ProducerConsumer 生成者消费者模式

本文主要是介绍设计模式 Concurrency 之 ProducerConsumer 生成者消费者模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 定义
  • 优缺点
  • 例子

1. 定义

某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

2. 优缺点

优点:

  • 解耦
    • 假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
  • 支持并发
    • 生产者和消费者可以是两个独立的并发主体,生产者只需要把数据放入数据缓冲区便可继续去生产,不用依赖于消费的处理速度

3. 例子

这里写图片描述

Item

package com.hqq.concurrency.producer_consumer;/*** Item* Created by heqianqian on 2017/8/1.*/
public class Item {private String producer;private Integer id;public Item(String producer, Integer id) {this.producer = producer;this.id = id;}public String getProducer() {return producer;}public Integer getId() {return id;}
}

ItemQueue[内部使用的是BlockingQueue阻塞队列 当队列中没有元素 会阻塞等待]

package com.hqq.concurrency.producer_consumer;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;/*** ItemQueue* Created by heqianqian on 2017/8/1.*/
public class ItemQueue {private BlockingQueue<Item> queue;public ItemQueue() {queue = new LinkedBlockingQueue<>(5);}public void put(Item item) throws InterruptedException {queue.put(item);}public Item take() throws InterruptedException {return queue.take();}}

Producer

package com.hqq.concurrency.producer_consumer;import java.util.Random;/*** Producer* 生产者* Created by heqianqian on 2017/8/1.*/
public class Producer {private final ItemQueue queue;private final String name;private int itemId;public Producer(String name, ItemQueue queue) {this.name = name;this.queue = queue;}/*** Put item in the queue*/public void produce() throws InterruptedException {Item item = new Item(name, itemId++);queue.put(item);Random random = new Random();Thread.sleep(random.nextInt(2000));}
}

Consumer

package com.hqq.concurrency.producer_consumer;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** Consumer* 消费者* Created by heqianqian on 2017/8/1.*/
public class Consumer {private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class);private final ItemQueue queue;private final String name;public Consumer(String name, ItemQueue queue) {this.name = name;this.queue = queue;}/*** Consume item from the queue*/public void consume() throws InterruptedException {Item item = queue.take();LOGGER.info("Consumer [{}] consume item [{}] produced by [{}]", name, item.getId(), item.getProducer());}
}

APP

package com.hqq.concurrency.producer_consumer;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;/*** App* Created by heqianqian on 2017/8/1.*/
public class App {private static final Logger LOGGER = LoggerFactory.getLogger(App.class);public static void main(String... args) {ItemQueue queue = new ItemQueue();ExecutorService executorService = Executors.newFixedThreadPool(5);for (int i = 0; i < 2; i++) {final Producer producer = new Producer("Producer_" + i, queue);executorService.submit(() -> {while (true) {producer.produce();}});}for (int i = 0; i < 3; i++) {final Consumer consumer = new Consumer("Consumer_" + i, queue);executorService.submit(() -> {while (true) {consumer.consume();}});}executorService.shutdown();try {executorService.awaitTermination(10, TimeUnit.SECONDS);executorService.shutdownNow();} catch (InterruptedException e) {LOGGER.error("Error waiting for ExecutorService shutdown");}}}

运行结果:

INFO  [2017-08-09 02:40:51,891] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_0] consume item [0] produced by [Producer_1]
INFO  [2017-08-09 02:40:51,891] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_1] consume item [0] produced by [Producer_0]
INFO  [2017-08-09 02:40:52,270] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_2] consume item [1] produced by [Producer_1]
INFO  [2017-08-09 02:40:53,085] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_0] consume item [1] produced by [Producer_0]
INFO  [2017-08-09 02:40:53,822] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_1] consume item [2] produced by [Producer_0]
INFO  [2017-08-09 02:40:53,853] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_2] consume item [2] produced by [Producer_1]
INFO  [2017-08-09 02:40:54,721] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_0] consume item [3] produced by [Producer_1]
INFO  [2017-08-09 02:40:55,474] com.hqq.concurrency.producer_consumer.Consumer: Consumer [Consumer_1] consume item [4] produced by [Producer_1]
...

这篇关于设计模式 Concurrency 之 ProducerConsumer 生成者消费者模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/867452

相关文章

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

Python实现自动化Word文档样式复制与内容生成

《Python实现自动化Word文档样式复制与内容生成》在办公自动化领域,高效处理Word文档的样式和内容复制是一个常见需求,本文将展示如何利用Python的python-docx库实现... 目录一、为什么需要自动化 Word 文档处理二、核心功能实现:样式与表格的深度复制1. 表格复制(含样式与内容)2

python如何生成指定文件大小

《python如何生成指定文件大小》:本文主要介绍python如何生成指定文件大小的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python生成指定文件大小方法一(速度最快)方法二(中等速度)方法三(生成可读文本文件–较慢)方法四(使用内存映射高效生成

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

Maven项目中集成数据库文档生成工具的操作步骤

《Maven项目中集成数据库文档生成工具的操作步骤》在Maven项目中,可以通过集成数据库文档生成工具来自动生成数据库文档,本文为大家整理了使用screw-maven-plugin(推荐)的完... 目录1. 添加插件配置到 pom.XML2. 配置数据库信息3. 执行生成命令4. 高级配置选项5. 注意事

MybatisX快速生成增删改查的方法示例

《MybatisX快速生成增删改查的方法示例》MybatisX是基于IDEA的MyBatis/MyBatis-Plus开发插件,本文主要介绍了MybatisX快速生成增删改查的方法示例,文中通过示例代... 目录1 安装2 基本功能2.1 XML跳转2.2 代码生成2.2.1 生成.xml中的sql语句头2

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到