java实现多线程生产者消费者模式
1、概念
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
在实际生活中,老师和学生的关系就是一种生产者消费者模型,老师负责布置作业(生产),学生负责写作业(消费)。还有餐馆厨师负责做饭(生产),顾客负责吃饭(消费)等等。
2、参与对象
生产者:负责向缓冲区存放数据
消费者:负责从缓冲区读取数据
缓冲区:负责存放数据
3、优点
3.1、解耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
3.2、支持并发
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体(常见并发类型有进程和线程两种,后面的帖子会讲两种并发类型下的应用)。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。
其实当初这个模式,主要就是用来处理并发问题的。
3.3、支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
4、代码实现
说明:例子模拟生产者(Producer)消费者(Consumer)模式,其中缓冲区(Bean),当缓冲区数据达到10(FULL),生产者停止生产数据,当缓冲区没有数据,消费者停止消费数据。
4.1、Bean
public class Bean {
private Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
4.2、生产者
public class Producer implements Runnable {private Bean bean;
private static final Integer FULL = 10;
public Producer(Bean bean) {
this.bean = bean;
}
private void produce() throws InterruptedException {
while (true){
Thread.sleep(1000);
synchronized (bean) {
if (bean.getCount() >= FULL) {
System.out.println("生产者等待");
bean.wait();
}
else {
bean.setCount(bean.getCount() + 1);
System.out.println(Thread.currentThread().getName() + "生产, current :" + bean.getCount());
bean.notifyAll();
}
}
}
}
@Override
public void run() {
try {
produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.3、消费者
public class Consumer implements Runnable {
private Bean bean;
private static final Integer NULL = 0;
public Consumer(Bean bean) {
this.bean = bean;
}
private void consume() throws InterruptedException {
while (true) {
Thread.sleep(2000);
synchronized (bean) {
if (bean.getCount() <= NULL) {
System.out.println("消费者等待");
bean.wait();
}
else {
bean.setCount(bean.getCount() - 1);
System.out.println(Thread.currentThread().getName() + "消费, current :" + bean.getCount());
bean.notifyAll();
}
}
}
}
@Override
public void run() {
try {
consume();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.4、main
public class Test {
public static void main(String[] args) {
Bean bean = new Bean();
bean.setCount(0);
for (int i = 0; i < 5; i++) {
new Thread(new Producer(bean)).start();
new Thread(new Consumer(bean)).start();
}
}
}
4.5、输出
Thread-0生产, current :1
Thread-8生产, current :2
Thread-2生产, current :3
Thread-6生产, current :4
Thread-4生产, current :5
Thread-2生产, current :6
Thread-7消费, current :5
Thread-9消费, current :4
Thread-0生产, current :5
Thread-3消费, current :4
Thread-1消费, current :3
Thread-8生产, current :4
Thread-6生产, current :5
Thread-5消费, current :4
Thread-4生产, current :5
Thread-8生产, current :6
Thread-2生产, current :7
Thread-0生产, current :8
Thread-4生产, current :9
Thread-6生产, current :10
生产者等待
生产者等待
为什么要在count外面套一层Bean?不直接使用count呢
原因是缓冲区(count)需要对生产者消费者共享,synchronize不能锁Integer对象(操作Integer对象的时候,自动装箱/拆箱对象就已经变了,会失去同步的效果)
5、总结
以上是通过wait()/notifyAll()实现的生产者消费者模式,也是比较简单的一种实现方式,除此之外还有通过await() / signal()方法、BlockingQueue阻塞队列方法、信号量、管道等方法实现。
java实现多线程生产者消费者模式的更多相关文章
- java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】
java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...
- Java实现多线程生产者消费者模式的两种方法
生产者消费者模式:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据.生产者生产一个,消费者消费一个,不断循环. 第一种实现方法,用BlockingQueue阻塞队 ...
- Java设计模式之生产者消费者模式
Java设计模式之生产者消费者模式 博客分类: 设计模式 设计模式Java多线程编程thread 转载 对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一 ...
- java多线程 生产者消费者模式
package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...
- Java 并发编程 生产者消费者模式
本文部分摘自<Java 并发编程的艺术> 模式概述 在线程的世界里,生产者就是生产数据的线程,消费者就是消费数据的数据.生产者和消费者彼此之间不直接通信,而是通过阻塞队列进行通信,所以生产 ...
- java设计模式之生产者/消费者模式
什么是生产者/消费者模式? 某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.线程.进程等).产生数据的模块,就形象地称为生产者:而处理数据的模块,就称为消费者 ...
- Java实现多线程生产者消费者模型及优化方案
生产者-消费者模型是进程间通信的重要内容之一.其原理十分简单,但自己用语言实现往往会出现很多的问题,下面我们用一系列代码来展现在编码中容易出现的问题以及最优解决方案. /* 单生产者.单消费者生产烤鸭 ...
- Java多线程-----实现生产者消费者模式的几种方式
1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理 ...
- 【多线程】java多线程实现生产者消费者模式
思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...
随机推荐
- 第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证
第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证 这是密码学52件事系列中第16篇,这周我们描述关于DSA,Schnorr和RSA-FDH的密钥生成,签名和验证. 1. ...
- Propensity Scores
目录 基本的概念 重要的结果 应用 Propensity Score Matching Stratification on the Propensity Score Inverse Probabili ...
- CHARACTERIZING ADVERSARIAL SUBSPACES USING LOCAL INTRINSIC DIMENSIONALITY
目录 概 主要内容 LID LID估计 算法 实验 1 2 3 4 5 Ma X, Li B, Wang Y, et al. Characterizing Adversarial Subspaces ...
- 网易云 微专业C++系统工程师
网易云 微专业C++系统工程师 一.学前基础 1.曾经学过某种编程语言(C语言最佳) 2.了解基本的变量.类型.作用域.循环和控制流程:了解基本数据类型(整数.浮点.字符串.数组等) 3.知道如何编译 ...
- C++模拟python风格的print函数--打印vector,map,list等结构
// 最基本实现 template<typename T> static void print(T t) { std::cout << t; } // 处理 std::pair ...
- Java Web项目 慧心人力资源管理系统
题目:慧心人力资源管理系统 文档下载:https://download.csdn.net/download/weixin_44893902/16336711 完整项目下载:https://downlo ...
- js 中&&的使用
遇到下列代码goHome && (await router.replace(PageEnum.BASE_HOME)); &&这个逻辑与的作用是,当goHome为true ...
- linux centos7 修改文件启动报错如何拯救
系统无法启动 CentOS启动的时候读条已经读满,但是没有反应,按下f5键跳出启动列表,最后一条信息:A start job is running for /etc/rc.d/rc.local Com ...
- Servlet简单实现开发部署过程
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6512008683445027331/ 主要是从下面三个步骤实现我们的预期: (1)构建开发环境: (2)开发Ser ...
- 谱分解(SD)
前提:矩阵A必须可相似对角化! 充分条件: $A$ 是实对称矩阵 $A$ 有 $n$ 个互异特征值 $A^{\wedge} 2=A $ $\mathrm{A}^{\wedge} 2=\mathrm{E ...