(一)生产者消费者模式原理:

在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。生产消费者模式如下图:

(二)代码实现

生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好。最关键就是内存缓冲区为空的时候消费者必须等待,而内存缓冲区满的时候,生产者必须等待。其他时候可以是个动态平衡:
 

首先设置Market类:
其中变量有:Max(仓库最大值),List(用于存放数据)
方法有Producer(生产方法),Cost(消费方法)

public class Market{private int Max=20;private List<String>list=new ArrayList<String>();public synchronized void producer()throws InterruptedException{             //设置锁if(list.size()>=20){this.wait():                       //超过容量时,等待}System.out.println("***开始生产,现在数量为"+list.size()); list.add("a");System.out.println("***生产后数量为"+list.size());this.notify();                 //唤醒线程}public synchronized void cost()throws InterruptedException{if(list.size()<0){this.wait();                     //线程休眠}System.out.println("开始消费,现在数量为:"+list.size());list.remove(0);System.out.println("消费后数量为:"+list.size());this.notify();                      //唤醒线程}
}

其次分别时Producer和Cost类,都要继承Thread类,重写run方法

public class Producer extends Thread{                //继承run方法private Market market;public Producer(Market market){this.market=market;}public void run(){while(true) {try {Thread.sleep(new Random().nextInt(500));     //设置时间延迟} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {market.production();                              //调用生产方法} catch (InterruptedException e) {             // TODO Auto-generated catch blocke.printStackTrace();}}}
public class Cost extends Thread{                //继承run方法private Market market;public Cost(Market market){this.market=market;}public void run(){while(true) {try {Thread.sleep(new Random().nextInt(500));     //设置时间延迟} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {market.cost();                              //调用消费方法} catch (InterruptedException e) {             // TODO Auto-generated catch blocke.printStackTrace();}}}

最后写出测试类,启动线程

public class Test{public static void main(String[]args){Market market=new Market();Producer p1=new Producer(market);Producer p2=new Producer(market);Producer p3=new Producer(market);Cost c1=new Cost(market);Cost c2=new Cost(market);p1.start();                //启动线程p2.start();p3.start();c1.start();c2.start();}
}

得到的运行结果为:

可知模拟的生产者消费者模式

(三)代码关键点分析:

1.锁问题:

对于Market中的Producer方法和Cost方法,要使用Synchronized关键字同步非静态方法,且要与wait()方法放在一起,使得在多个消费者生产者线程访问Market中的共享资源时不会发生线程安全问题,并且可以保证锁的时同一个对象

  public synchronized void producer()public synchronized void cost ()

2.线程的等待与重启

在生产时达到仓库的最大值后,要停止生产,即让生产的线程处于等待状态,此时需要调用wait()方法,

if(list.size()>=20){this.wait();                     //线程休眠}
                this.notify();                 //唤醒线程

要用this来调用wait()方法,而不能用list,是因为被加锁的对象this在调用wait()和notify(),加锁的对象调用 wait() 方法后,线程进入等待状态,直到在加锁的对象上调用 notify() 方法来唤醒之前进入等待的线程

3.While循环放置在Producer和Cost类的run方法中:

使用while循环是原因:要保证线程可以一直运行下去:

   public void run(){while(true) {try {Thread.sleep(new Random().nextInt(500));     //设置时间延迟} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {market.cost();                              //调用消费方法} catch (InterruptedException e) {             // TODO Auto-generated catch blocke.printStackTrace();}}

如果把while循环放在Market中,则睡眠的线程被唤醒之后有可能不满足while()中的条件判定,使得线程线程无法再调用Market中的producer方法,从而无法唤醒线程,因此要放在线程外

4.时间延迟问题:

若要模拟生产和消费的随机过程,还要设置时间延迟

  public void run(){while(true) {try {Thread.sleep(new Random().nextInt(500));     //设置时间延迟} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {market.cost();                              //调用消费方法} catch (InterruptedException e) {             // TODO Auto-generated catch blocke.printStackTrace();}}

放在Producer类中的原因是只有放在run方法中,线程运行时才会具有随机性
否则会发生只有生产达到最大值后才会开始消费

(四)生产者消费者模式相关推荐

  1. [19/04/11-星期四] 多线程_并发协作(生产者/消费者模式_2种解决方案(管程法和信号灯法))...

    一.概念 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型"生产者/消费者模式". Ø 什么是生产者? 生产者指的是负责生产数据的模 ...

  2. Java中设计模式之生产者消费者模式-3

    引言 生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区.其中一个是生产者,用于将消息放入缓冲区:另 ...

  3. 手撕生产者-消费者模式 | P问题、NP问题

    目录 手撕BlockingQueue 生产者-消费者模式 P问题.NP问题 手撕BlockingQueue public class RequestQueue {private final Queue ...

  4. 并发编程(五)python实现生产者消费者模式多线程爬虫

    并发编程专栏系列博客 并发编程(一)python并发编程简介 并发编程(二)怎样选择多线程多进程和多协程 并发编程(三)Python编程慢的罪魁祸首.全局解释器锁GIL 并发编程(四)如何使用多线程, ...

  5. 生产者/消费者模式的理解及实现

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

  6. 【Java】生产者消费者模式的三种实现

    原文地址:https://blog.csdn.net/u010983881/article/details/78554671 前言 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内 ...

  7. 关于生产者消费者模式的C#实现

    今天是圣诞节,大家 Merry Chrismas~ 以前都是在C++项目中写界面,现在接触了C#感觉比MFC和QT好用多了,决定以后除了特殊要求外都用C#开发:).记录一下用C#实现生产者消费者模式吧 ...

  8. Java多线程(含生产者消费者模式详解)

    多线程 导航 多线程 1 线程.进程.多线程概述 2 创建线程 (重点) 2.1 继承Thread类(Thread类也实现了Runnable接口) 2.2 实现Runnable接口(无消息返回) 2. ...

  9. 【Java】生产者消费者模式的实现

    前言 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.这个 ...

最新文章

  1. windows 10 代理服务器出现问题
  2. 第一章 MongoDb概述
  3. node 升级_技术周刊( Node.js 12 性能大提升 2019-04-30)
  4. HTML-参考手册: HTTP 方法:GET 对比 POST
  5. 《Spark核心技术与高级应用》——1.2节Spark的重要扩展
  6. 【微信小程序】wx:for
  7. 如果 “ 2X ”的补码是“ 90H ”,那么 X 的真值是( )。
  8. Request_获取请求体数据
  9. 论文阅读(2)--Picking Deep Filter Responses for Fine-grained Image Recognition
  10. sklearn查看数据
  11. Alec jacobson thesis analysis
  12. 若依微服务部署遇到问题
  13. 说出来你可能不信,内核这家伙在内存的使用上给自己开了个小灶!
  14. 抖音主页头图怎么设置,掌握以下5点技巧即可丨国仁网络资讯
  15. 什么是APS计划排程系统和生产计划排产系统?
  16. 禁用计算机的声卡设备,电脑声音被禁用了怎么办
  17. 计算机二级选择题笔记百度云,计算机二级题库及计算机二级ms office 复习笔记.doc...
  18. 【1错笔记】psd面试——最长回文子序列 动态规划(2000字超详细解题)
  19. 百亿富翁 (单调栈)
  20. 粒子群算法之01背包问题(C语言实现)

热门文章

  1. Docker harbor私有仓库部署与管理
  2. 中国电子学会2021年03月份青少年软件编程Scratch图形化等级考试试卷四级真题(含答案)
  3. 从携程瘫痪事件看运维的85条军规
  4. (一)什么是1588?1588的前世今生?1588的时间同步原理
  5. 如何在别人抖音直播间获客
  6. GF(Go Frame)生产级Go基础开发框架入门
  7. Excel 电子表格运用技巧汇总
  8. Arduino CNC电机扩展板详解(A4988驱动42步进电机)
  9. 编程实现根据指定文本生成电子印章
  10. 微信小程序插件下发优惠券踩坑