点击查看原文: http://www.joyhwong.com/2016/11/19/并发设计模式之生产者-消费者模式/

生产者-消费者模式是一个经典的多线程设计模式,它为多线程间的协作提供了良好的解决方案。在生产者-消费者模式中,通常有两类线程,即若干个生产者和若干个消费者线程。生产者线程负责提交用户请求,消费者线程则负责处理生产者提交的任务。生产者和消费者之间通过共享内存缓冲区进行通信

如图展示了生产者-消费者模式的基本结构。3个生产者线程将在任务提交到共享内存缓冲区,消费者线程并不直接与生产者线程通信,而在共享内存缓冲区中获取任务,并进行处理

生产者-消费者模式中的内存缓冲区的主要功能是数据在多线程间的共享。此外,通过该缓冲区,可以缓解生产者和消费者间的性能差

生产者-消费者模式的核心组件是共享内存缓冲区,它作为生产者和消费者间的通信桥梁,避免了生产者和消费者的直接通信,从而将生产者和消费者进行解耦。生产者不需要知道消费者的存在,消费者也不需要知道生产者的存在。同时,由于内存缓冲区的存在,允许生产者和消费者在执行速度上存在时间差,无论是生产者在某一局部时间内速度高于消费者,或者消费者在局部时间内高于生产者,都可以通过共享内存缓冲区得到缓解,确保系统正常运行

生产者-消费者模式的主要角色有:生产者、消费者、内存缓冲区、任务、Main

  • 生产者:用于提交用户请求,提取用户任务,并装入内存缓冲区
  • 消费者:在内存缓冲区中提取并处理任务
  • 内存缓冲区:缓存生产者提交的任务或数据,供消费者使用
  • 任务:生产者想内存缓冲区提交的数据结构
  • Main:使用生产者和消费者的客户端

上图显示了生产者-消费者模式一种实现的具体结构

其中,BlockingQueue充当了共享内存缓冲区,用户维护任务或数据队列(PCData对象)。PCData对象表示一个生产任务,或者相关任务的数据。生产者对象和消费者对象均引用同一个BlockingQueue实例。生产者负责创建PCData对象,并将它加入BlockingQueue中,消费者则从BlockingQueue队列中获取PCData

下面实现一个基于生产者-消费者模式的求证书平方的并行程序

PCData作为生产者和消费者之间的共享数据模型,定义如下

package com.joyhwong;public final class PCData {private final int intData;public PCData(int intData) {this.intData = intData;}public PCData(String d) {this.intData = Integer.valueOf(d);}public int getData() {return intData;}@Overridepublic String toString() {return "data: " + intData;}
}

生产者线程的实现如下

package com.joyhwong;import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;public class Producer implements Runnable {private volatile boolean isRunning = true;private BlockingQueue<PCData> queue;private static AtomicInteger count = new AtomicInteger();private static final int SLEEPTIME = 1000;public Producer(BlockingQueue<PCData> queue) {this.queue = queue;}@Overridepublic void run() {PCData data = null;Random random = new Random();System.out.println("start producer id = " + Thread.currentThread().getId());try {while (isRunning) {Thread.sleep(random.nextInt(SLEEPTIME));data = new PCData(count.incrementAndGet());System.out.println(data + " is put into queue");if (!queue.offer(data, 2, TimeUnit.SECONDS)) {System.out.println("failed to put data: " + data);}}} catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}public void stop() {isRunning = false;}
}

消费者实现如下,它从BlockingQueue队列中取出PCData对象,并进行相应的计算

package com.joyhwong;import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;public class Consumer implements Runnable {private BlockingQueue<PCData> queue;private static final int SLEEPTIME = 1000;public Consumer(BlockingQueue<PCData> queue) {this.queue = queue;}@Overridepublic void run() {System.out.println("Start Consumer id = " + Thread.currentThread().getId());Random random = new Random();try {while (true) {PCData data = queue.take();if (null != data) {int re = data.getData() * data.getData();System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(), data.getData(), re));Thread.sleep(random.nextInt(SLEEPTIME));}} } catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}
}

在主函数中,创建3个生产者和3个消费者,并让它们协作运行。在主函数的实现中,定义LinkedBlockingQueue作为BlockingQueue的实现类

package com.joyhwong;import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;public class Consumer implements Runnable {private BlockingQueue<PCData> queue;private static final int SLEEPTIME = 1000;public Consumer(BlockingQueue<PCData> queue) {this.queue = queue;}@Overridepublic void run() {System.out.println("Start Consumer id = " + Thread.currentThread().getId());Random random = new Random();try {while (true) {PCData data = queue.take();if (null != data) {int re = data.getData() * data.getData();System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(), data.getData(), re));Thread.sleep(random.nextInt(SLEEPTIME));}} } catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}
}

生产者-消费者模式能够很好地对生产者和消费者线程进行解耦,优化了系统整体结构。同时,由于缓冲区的作用,允许生产者线程和消费者线程存在执行上的性能差异,从一定程度上缓解了性能瓶颈对系统性能的影响。

并发设计模式之生产者-消费者模式相关推荐

  1. java消费者生产者设计模式_java 多线程并发设计模式之四: 生产者消费者模式

    生产者消费者模式是一个经典的多线程设计模式,其核心思想是:有两类线程和一个内存缓冲区或者队列, 一类线程发起任务,并提交到队列中.另一类线程用来处理这些任务,叫做消费者线程. 这两类线程进行通信的桥梁 ...

  2. delphi生产者消费者模式代码_并发设计模式:生产者-消费者模式,并发提高效率...

    生产者 - 消费者模式在编程领域的应用非常广泛,前面我们曾经提到,Java 线程池本质上就是用生产者 - 消费者模式实现的,所以每当使用线程池的时候,其实就是在应用生产者 - 消费者模式. 当然,除了 ...

  3. Java并发编程(二十三)------并发设计模式之生产者消费者模式

    参考文章:Java实现生产者消费者问题与读者写者问题 目录 1. 生产者消费者问题 1.1 wait() / notify()方法 1.2 await() / signal()方法 1.2.1 对sy ...

  4. 设计模式之生产者消费者模式

    简介 通过前几篇文章的学习,我想你已经彻底掌握了wait()方法和notify()方法如何使用以及在哪种情况下使用了,本片文章我们将讲解下设计模式中的生产者消费者模式,我将通过手写一份生产者消费者模式 ...

  5. Java并发编程实战~生产者-消费者模式

    前面我们在<Worker Thread 模式>中讲到,Worker Thread 模式类比的是工厂里车间工人的工作模式.但其实在现实世界,工厂里还有一种流水线的工作模式,类比到编程领域,就 ...

  6. 多线程-并发编程(7)-生产者消费者模式及非阻塞队列与阻塞队列实现

    生产者消费者模式是一个十分经典的多线程协作模式 弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻 存在3个元素 1.生产者(类比厨师) 2.生产者的生产产品(类比美食) 3.消费者(类比吃货) ...

  7. 并发协作模型“生产者/消费者模式“

    java提供了几个方法解决线程之间的通信问题 方法名 作用 wait() 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 wait(long timeout) 指定等待的毫秒数 not ...

  8. 并发设计模式之生产者消费者设计模式

    主函数: 1 package com.ietree.basicskill.mutilthread.designpattern.ProducerConsumer; 2 3 import java.uti ...

  9. 聊聊并发——生产者消费者模式

    在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据 ...

最新文章

  1. WordPress更新时提示无法连接到FTP服务器的解决方案
  2. 姚期智:中国金融科技发展的真正挑战是什么?如何解决? 本文作者:温晓桦 2017-09-17 18:31 导语:“在金融科技里面,计算机科学的用途已经从台后走到了台中,对核心金融体系的运作上产生一定的
  3. 救命,Linux正在吃掉我的内存!
  4. lame,把ios录音转换为mp3格式
  5. controller是什么意思_SpringMVC是什么??
  6. angularjs mysql_AngularJS SQL
  7. UVA - 213 Message Decoding
  8. 连续系统PID及其离散化 位置式PID以及增量式PID
  9. 月薪10000在中国是什么水平?
  10. 开源的一个java 写的图床
  11. excel 使用定位工具批量删除错误值
  12. Arduino uno LED灯实验
  13. 统计学习基础(第二版)——引言
  14. [JPA错误]javax.persistence.EntityNotFoundException: Unable to find xxx
  15. WIN10系统安装金蝶K3 WISE14.0以下客户端版本
  16. 网络规划师学习-二层交换机工作原理和二层交换机为啥不能跨网段通信
  17. 详细步骤:pytorch pth转wts转tensorrt(自定义模型,不用parser)
  18. rockchip mpp编码开发
  19. postgreSQL 获取当前连接的IP
  20. CSS3画三角形、菱形、平行四边形

热门文章

  1. 我的2012移动开发年度总结——革命的一年
  2. 2.python数据结构的性能分析
  3. Linux学习笔记(PATH,cp,mv,文档查看cat/more/less/head/tail)
  4. ASP.NET Core 使用 Hangfire 定时任务
  5. PSU更新之后是否更改数据库版本号呢
  6. 如何编写有效的Bug Report
  7. Discuz支持反对提示:抱歉您的请求来路不正确或表单无法提交的解决方法
  8. 获取Java项目根目录
  9. HackerOne漏洞奖励计划扩展至开源漏洞
  10. 谷歌 Compute Engine 的虚拟机曝0day未修复,可遭接管