java设计模式之生产者/消费者模式
什么是生产者/消费者模式?
某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式。结构图如下:

生产者消费者模式有如下几个优点:
1、解耦
由于有缓冲区的存在,生产者和消费者之间不直接依赖,耦合度降低。
2、支持并发
由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。
3、支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来 了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。
生产者-消费者模型准确说应该是“生产者-仓储-消费者”模型,这样的模型遵循如下的规则:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费
此模型将要结合java.lang.Object的wait与notify、notifyAll方法来实现以上的需求。实例代码如下:
创建所谓的“仓库”,此类是(本质上:共同访问的)共享数据区域
//此类是(本质上:共同访问的)共享数据区域
public class SyncStack { private String[] str = new String[10]; private int index; //供生产者调用
public synchronized void push(String sst){
if(index == sst.length()){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();//唤醒在此对象监视器上等待的单个线程
str[index] = sst;
index++;
} //供消费者调用
public synchronized String pop(){
if(index == 0){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
index--;
String product = str[index];
return product; } //就是定义一个返回值为数组的方法,返回的是一个String[]引用
public String[] pro(){
return str;
}
}
创建生产者:
public class Producter implements Runnable {
private SyncStack stack;
public Producter(SyncStack stack){
this.stack = stack;
}
public void run(){
for(int i = 0;i<stack.pro().length;i++){
String producter = "产品" + i;
stack.push(producter);
System.out.println("生产了:" + producter);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
创建消费者:
public class Consumer implements Runnable {
private SyncStack stack;
public Consumer(SyncStack stack){
this.stack = stack;
}
public void run(){
for(int i=0;i<stack.pro().length;i++){
String consumer = stack.pop();
System.out.println("消费了:" + consumer );
try {
Thread.sleep(400);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
测试类:
public class TestDeam {
public static void main(String[] args) {
SyncStack stack = new SyncStack();
Consumer p = new Consumer(stack);
Producter c = new Producter(stack);
new Thread(p).start();
new Thread(c).start();
}
}
测试结果:
生产了:产品0
消费了:产品0
生产了:产品1
生产了:产品2
消费了:产品2
生产了:产品3
消费了:产品3
生产了:产品4
生产了:产品5
生产了:产品6
消费了:产品5
生产了:产品7
消费了:产品6
消费了:产品7
生产了:产品8
生产了:产品9
消费了:产品8
消费了:产品9
消费了:产品4
消费了:产品1
java设计模式之生产者/消费者模式的更多相关文章
- Java设计模式之生产者消费者模式
Java设计模式之生产者消费者模式 博客分类: 设计模式 设计模式Java多线程编程thread 转载 对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一 ...
- java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】
java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...
- Java多线程-----实现生产者消费者模式的几种方式
1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理 ...
- 【多线程】java多线程实现生产者消费者模式
思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...
- Java实现多线程生产者消费者模式的两种方法
生产者消费者模式:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据.生产者生产一个,消费者消费一个,不断循环. 第一种实现方法,用BlockingQueue阻塞队 ...
- Java多线程_生产者消费者模式2
在我的上一条博客中,已经介绍到了多线程的经典案列——生产者消费者模式,但是在上篇中用的是传统的麻烦的非阻塞队列实现的.在这篇博客中我将介绍另一种方式就是:用阻塞队列完成生产者消费者模式,可以使用多种阻 ...
- Java 并发编程 生产者消费者模式
本文部分摘自<Java 并发编程的艺术> 模式概述 在线程的世界里,生产者就是生产数据的线程,消费者就是消费数据的数据.生产者和消费者彼此之间不直接通信,而是通过阻塞队列进行通信,所以生产 ...
- Java多线程编程——生产者-消费者模式(1)
生产者-消费者模式在生活中非常常见.就拿我们去餐馆吃饭为例.我们会遇到以下两种情况: 1.厨师-客人 如下图所示,生产者.消费者直接进行交互. 生产者生产出产品后,通知消费者:消费者消费后,通知生产者 ...
- JAVA多线程之生产者 消费者模式 妈妈做面包案例
创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包 最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...
随机推荐
- 操作 frames 框架下的 dom 内容。
2016-12-30 框架名: var obj=$(window.frames["wangpan"].document).find("a[menu=download_on ...
- 5+ App开发打包指南
HTML5 Plus应用概述 HTML5 Plus移动App,简称5+App,是一种基于HTML.JS.CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任意调用手机的原生能力,实 ...
- error LNK2019-无法解析的外部符号 _main-该符号在函数 ___tmainCRTStartup 中被引用
问题分析: 因为Win32 console Application的入口函数是Main(),而Win32 Application的入口函数才是WinMain() 解决方案: 右键项目,打开[属性]页, ...
- 基于 Python 和 Pandas 的数据分析(1)
基于 Python 和 Pandas 的数据分析(1) Pandas 是 Python 的一个模块(module), 我们将用 Python 完成接下来的数据分析的学习. Pandas 模块是一个高性 ...
- animate.css –齐全的CSS3动画库--- 学习笔记
animate.css – 齐全的CSS3动画库 学习网站: https://daneden.github.io/animate.css/ http://www.dowebok.com/98.html ...
- overload、override、overwrite的介绍
答:(1)overload(重载),即函数重载: ①在同一个类中: ②函数名字相同: ③函数参数不同(类型不同.数量不同,两者满足其一即可): ④不以返回值类型不同作为函数重载的条件. (2)over ...
- Spring的一个入门例子
例子参考于:Spring系列教材 以及<轻量级JavaEE企业应用实战> Axe.class package com.how2java.bean; public class Axe { p ...
- 如何编写一个d.ts文件
这篇文章主要讲怎么写一个typescript的描述文件(以d.ts结尾的文件名,比如xxx.d.ts). 2018.12.18更新说明: 1.增加了全局声明的原理说明. 2.增加了es6的import ...
- icehouse版本中常用操作命令
•Glance操作常用命令1,列出所有镜像.glance image-list 2,显示某个image的详细信息.glance image-show 某个image的ID. 3,获得命令的帮助.gla ...
- 第 3 章 镜像 - 013 - Dockerfile 构建镜像
第一个 Dockerfile FROM ubuntu RUN apt-get update && apt-get install -y vim 运行 docker build 命令构建 ...