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 ...
随机推荐
- [opencv]膨胀腐蚀
Mat dilateimg; Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); dilate(canny, dilateimg, ...
- 市场上十块钱买一个随身WiFi使用技术手段,插卡流量不限速不限量?
全部章节 >>>> 文章目录 一.前言 二.进入安卓界面 1.进入网页控制台 2.先开启adb 3.CMD连接设备 4.对界面进行控制 三.刷入clnc脚本实现免流 1.ADB ...
- openmesh - impl - Remove Duplicated Vertices
openmesh - impl - Remove Duplicated Vertices 关于openmesh元素删除实现的介绍参见:openmesh - src - trimesh delete a ...
- unittest_认识unittest(1)
unittest是python内置的单元测试框架,具备编写用例.组织用例.执行用例.输出报告等自动化框架的条件. 使用unittest前需要了解该框架的五个概念: 即test case,test su ...
- 基于CentOS7.x gitlab环境搭建,卸载,汉化 --卸载篇
gitlab环境搭建,卸载,汉化 --卸载篇 完全卸载 停止gitlab gitlab-ctl stop 卸载gitlab rpm -e gitlab-ce 查看gitlab进程 ps aux | ...
- CentOS7 安装mysql并解决安装慢的问题
0.centOS7 mini版安装及网络配置 //可从我的网盘保存下载,可用虚拟机安装 链接:https://pan.baidu.com/s/10_AHxN0DtJ75s1oFOaaZ3A 密码:ud ...
- Nginx 负载均衡服务器的下载与安装 【window10】
1.前言 Nginx是什么? 找了下资料,解释 : Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器, ...
- react中prop-types的使用
什么是prop-types?prop代表父组件传递过来的值,types代表类型.简单来说就是用来校验父组件传递过来值的类型 import PropTypes from 'prop-types'; To ...
- Nacos配置管理最佳实践
Nacos一个最常用的功能就是配置中心,在具体使用时往往是多个团队,甚至整个公司的研发团队都使用同一个Nacos服务.那么使用时如何保证配置在各个团队之间的隔离,又能保证配置管理的便捷性?下面就来介绍 ...
- Mybatis配置解析(核心配置文件)
4.配置解析 4.1.核心配置文件 Mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息 mybatis-config.xml properties(属性)重点 settings ...