写一个固定容量同步容器,拥有put和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用。
1、synchronized同步方法

public class Container1<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10; //最多10个元素private int count = 0;//生产者public synchronized void put(T t) {while(lists.size() == MAX) { //使用while不断判断是否等于MAX值,当数量达到MAX值后使得生产线程阻塞,被消费一个便立刻结束循环唤醒生产线程try {this.wait(); //effective java} catch (InterruptedException e) {e.printStackTrace();}}lists.add(t);++count;this.notifyAll(); //֪ͨ通知消费者线程进行消费}//消费者public synchronized T get() {T t = null;while(lists.size() == 0) {//一旦数量等于0,便使消费线程阻塞try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}t = lists.removeFirst();count --;this.notifyAll(); //通知生产者线程进行生产return t;}public static void main(String[] args) {Container1<String> c = new Container1<>();//启动消费者线程for(int i=0; i<10; i++) {new Thread(()->{for(int j=0; j<5; j++) System.out.println(c.get());}, "c" + i).start();}try {Thread.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}//启动生产者线程for(int i=0; i<2; i++) {new Thread(()->{for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);}, "p" + i).start();}}
}

程序中定义了MAX变量来限制产品的总数,定义了count变量用来判断生产了几个 产品和消费了几个 产品,在put()方法中,首先判断 LinkedList集合中产品是否是MAX变量的值,如果是启动所有消费者线程,反之开始生产 产品,在get()方法中,首先判断是否还有 产品,也就是MAX的值是否为0,如果为0通知所有生产者线程开始生产 产品,反之不为0 产品数就继续减少,需要注意的点是,这里我们加了synchronized,因为++count生产产品变成新值时,一个线程还没来得及加的时候,咋们的count还为老值,另外一个线程读到的值很可能还不是最新值,所以不加锁就会出问题,main方法中通过for循环分别创建了2个生产者线程生产分别生产25个 产品,也就是50个产品,10个消费者线程每个消费者消费5个 产品,也就是50个 产品,首先启动消费者线程,然后启动生产者线程。

在判断容器中为空或者满的时候为什么用while而不是用if? 因为当LinkedList集合中产品数等于最大值的时,if在判断了集合的大小等于MAX的时候,调用了wait()方法以后,它不会再去判断一次,方法会继续往下运行,假如在你wait()以后,另一个方法又添加了一个产品,你没有再次判断,就又添加了一次,造成数据错误,就会出问题,因此必须用while。

注意看我们用的是notifyAll()来唤醒线程的,notifyAll()方法会叫醒等待队列的所有方法,那么我们都知道,用了锁以后就只有一个线程在运行,其他线程都得wait(),不管你有多少个线程,这个时候被叫醒的线程有消费者的线程和生产者的线程,所有的线程都会争抢这把锁,比如说我们是生产者线程,生产满了,满了以后我们叫醒消费者线程,可是很不幸的是,它同样的也会叫醒另外一个生产者线程,假如这个生产者线程拿到了刚才第一个生产者释放的这把锁,它又wait()一遍,wait()完以后,又叫醒全部的线程,然后又开始争抢这把锁,其实从这个意义上来讲,生产者的线程wait时,没有必要去叫醒别的生产者。

所以基于这样的考虑,我们生产者只叫醒消费者线程,消费者线程只负责叫醒生产者线程。
2、ReentrantLock锁

public class Container2<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10; //最多10个元素private int count = 0;private Lock lock = new ReentrantLock();//两个Condition,即两个同步队列private Condition producer = lock.newCondition();private Condition consumer = lock.newCondition();public void put(T t) {try {lock.lock();while(lists.size() == MAX) {producer.await();}lists.add(t);++count;consumer.signalAll(); //通知消费者线程进行消费} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public T get() {T t = null;try {lock.lock();while(lists.size() == 0) {consumer.await();}t = lists.removeFirst();count --;producer.signalAll(); //通知生产者进行生产} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return t;}public static void main(String[] args) {Container2<String> c = new Container2<>();//启动消费者线程for(int i=0; i<10; i++) {new Thread(()->{for(int j=0; j<5; j++) System.out.println(c.get());}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}//启动生产者线程for(int i=0; i<2; i++) {new Thread(()->{for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);}, "p" + i).start();}}
}

使用ReentrantLock与synchronized最大区别在于ReentrantLock它可以有两种Condition条件,即会有两个同步队列,一个是成产线程的同步队列,一个是消费者的同步队列,一但数量达到MAX峰值的时候调用producer.await(),使得生产线程全部阻塞,调用consumer.signalAll()唤醒全部消费者线程,也就是说我在producer的情况下阻塞的,我叫醒的只是consumer,同理在消费者线程使得数量为0的时候,我阻塞的全是消费者线程,叫醒的全是生产者线程,这就是ReentrantLock的含义,它能够精确的指定哪些线程被叫醒,我们来说一下Lock和Condition的本质是什么,在synchronized里调用wait()和notify()的时候,它只有一个等待队列,而lock.newnewCondition()的时候,有多少个Condition,则创建了多少个等待队列,Condition的本质就是等待队列个数,以前只有一个等待队列,现在我new了两个Condition,一个叫producer等待队列,另一个叫consumer的等待队列,当我们使用producer.await();的时候,指的是阻塞producer的等待队列中的线程,使用producer.signalAll()指的是唤醒producer这个等待队列的线程,consumner也是如此,在生产者线程里叫醒consumer等待队列的线程也就是消费者线程,在消费者线程里叫醒producer待队列的线程也就是生产者线程。

多线程——生产者消费者模型相关推荐

  1. python多线程实现生产者消费者_用Python实现多线程“生产者-消费者”模型的简单例子...

    用 Python 实现多线程"生产者 - 消费者"模型的简单例子 生产者消费者问题是一个著名的线程同步问题, 该问题描述如下: 有一个生产者在生产产品, 这些产品将提供给若干个消费 ...

  2. 多线程生产者消费者模型

    1. 基础知识: 1. 什么是生产者-消费者模式: 比如有两个进程A和B,它们共享一个固定大小的缓冲区,A进程产生数据放入缓冲区,B进程从缓冲区中取出数据进行计算,那么这里其实就是一个生产者和消费者的 ...

  3. Linux多线程——生产者消费者模型

    目录 一.生产者消费者模型 1.1 什么是生成者消费者模型 1.2 生产者消费者模型的优点 1.3 基于阻塞队列实现生产者消费者模型 1.4 POSIX信号量 1.4.1 信号量概念 1.4.2 P操 ...

  4. 多线程-生产者-消费者模型

    一.前言 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描 ...

  5. Linux基于单链表环形队列的多线程生产者消费者模型

    生产者–消费者模型简述 对于生产者–消费者模型,相信我们都不陌生,因为生活中,我们无时无刻不在扮演生产者或消费者.但是对于Linux中的生产者–消费者模型,大家又了解了一个什么程度? 其实,说白了就是 ...

  6. java多线程抽奖_java 线程池、多线程并发实战(生产者消费者模型 1 vs 10) 附案例源码...

    导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...

  7. C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)

    前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题--生产者消费者模型,并给出 ...

  8. Java多线程(十):BlockingQueue实现生产者消费者模型

    BlockingQueue BlockingQueue.解决了多线程中,如何高效安全"传输"数据的问题.程序员无需关心什么时候阻塞线程,什么时候唤醒线程,该唤醒哪个线程. 方法介绍 ...

  9. 【Java 并发编程】多线程、线程同步、死锁、线程间通信(生产者消费者模型)、可重入锁、线程池

    并发编程(Concurrent Programming) 进程(Process).线程(Thread).线程的串行 多线程 多线程的原理 多线程的优缺点 Java并发编程 默认线程 开启新线程 `Ru ...

最新文章

  1. Android实战简易教程-第三十四枪(基于ViewPager和FragmentPagerAdapter实现滑动通用Tab)...
  2. 巧用Windows 7命令,修复系统故障!
  3. grep、cut、awk、sed文本处理
  4. Linq使用Group By 1
  5. 解决Please choose a writable location using the '-configuration' command line option
  6. fastjson Features 说明
  7. 简单的学习心得:网易云课堂Android开发第六章SQLite与ContentProvider
  8. C#规范整理·集合和Linq
  9. 单向链表的简单Java实现-sunziren
  10. Python2.7编程基础(博主推荐)
  11. 页面内部DIV让点击外部DIV 事件不发生(阻止冒泡事件)
  12. python客户端服务器_Python客户端和服务器ch
  13. Java 最常见的 200+ 面试题:面试必备
  14. base64编码转图片格式
  15. 关于自己学习安卓的体会
  16. 一本书的推荐序——写在《思考的乐趣》即将上市之际
  17. 协方差意味着什么_微服务意味着我们可以使用所需的任何语言? 真?
  18. 统一门户:基于网关的统一用户认证方案
  19. C语言错误信息中文解释
  20. 网易考拉涉假疑案最新进展:雅诗兰黛中国承认没有鉴定真假的仪器

热门文章

  1. Http Digest 认证
  2. 【GANs】Conditional Generative Adversarial Nets
  3. 反向代理和正向代理之间的区别
  4. 【目标检测算法】YOLO-V5实战检测VOC2007数据集
  5. HTML的语义化理解
  6. 三个点在同一个半圆的概率_圆内任取三点/四点在同一半圆内的概率是多少?...
  7. 如何看待 12 月 26 日发布的华为云 WeLink 企业智能工作平台?能对标得过企业微信和钉钉吗?
  8. python sort函数
  9. Python进程池apply_async的callback函数不执行的解决方案
  10. 7-1 循环-古角猜想 (20 分)