转: 【Java并发编程】之十三:生产者—消费者模型(含代码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17249321
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
这里实现如下情况的生产--消费模型:
生产者不断交替地生产两组数据“姓名--1 --> 内容--1”,“姓名--2--> 内容--2”,消费者不断交替地取得这两组数据,这里的“姓名--1”和“姓名--2”模拟为数据的名称,“内容--1 ”和“内容--2 ”模拟为数据的内容。
由于本程序中牵扯到线程运行的不确定性,因此可能会出现以下问题:
1、假设生产者线程刚向数据存储空间添加了数据的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程将把信息的名称和上一个信息的内容联系在一起;
2、生产者生产了若干次数据,消费者才开始取数据,或者是,消费者取完一次数据后,还没等生产者放入新的数据,又重复取出了已取过的数据。
问题1很明显要靠同步来解决,问题2则需要线程间通信,生产者线程放入数据后,通知消费者线程取出数据,消费者线程取出数据后,通知生产者线程生产数据,这里用wait/notify机制来实现。
详细的实现代码如下:
- class Info{ // 定义信息类
- private String name = "name";//定义name属性,为了与下面set的name属性区别开
- private String content = "content" ;// 定义content属性,为了与下面set的content属性区别开
- private boolean flag = true ; // 设置标志位,初始时先生产
- public synchronized void set(String name,String content){
- while(!flag){
- try{
- super.wait() ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- }
- this.setName(name) ; // 设置名称
- try{
- Thread.sleep(300) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- this.setContent(content) ; // 设置内容
- flag = false ; // 改变标志位,表示可以取走
- super.notify();
- }
- public synchronized void get(){
- while(flag){
- try{
- super.wait() ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- }
- try{
- Thread.sleep(300) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- System.out.println(this.getName() +
- " --> " + this.getContent()) ;
- flag = true ; // 改变标志位,表示可以生产
- super.notify();
- }
- public void setName(String name){
- this.name = name ;
- }
- public void setContent(String content){
- this.content = content ;
- }
- public String getName(){
- return this.name ;
- }
- public String getContent(){
- return this.content ;
- }
- }
- class Producer implements Runnable{ // 通过Runnable实现多线程
- private Info info = null ; // 保存Info引用
- public Producer(Info info){
- this.info = info ;
- }
- public void run(){
- boolean flag = true ; // 定义标记位
- for(int i=0;i<10;i++){
- if(flag){
- this.info.set("姓名--1","内容--1") ; // 设置名称
- flag = false ;
- }else{
- this.info.set("姓名--2","内容--2") ; // 设置名称
- flag = true ;
- }
- }
- }
- }
- class Consumer implements Runnable{
- private Info info = null ;
- public Consumer(Info info){
- this.info = info ;
- }
- public void run(){
- for(int i=0;i<10;i++){
- this.info.get() ;
- }
- }
- }
- public class ThreadCaseDemo03{
- public static void main(String args[]){
- Info info = new Info(); // 实例化Info对象
- Producer pro = new Producer(info) ; // 生产者
- Consumer con = new Consumer(info) ; // 消费者
- new Thread(pro).start() ;
- //启动了生产者线程后,再启动消费者线程
- try{
- Thread.sleep(500) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- new Thread(con).start() ;
- }
- }
执行结果如下:
另外,在run方法中,二者循环的次数要相同,否则,当一方的循环结束时,另一方的循环依然继续,它会阻塞在wait()方法处,而等不到对方的notify通知。
转: 【Java并发编程】之十三:生产者—消费者模型(含代码)的更多相关文章
- 【Java并发编程】:生产者—消费者模型
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...
- 5 并发编程-(进程)-队列&生产者消费者模型
1.队列的介绍 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 创建队列的类(底层就是以管道和锁定的方式实现 ...
- Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition
在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...
- 【Java并发编程】从CPU缓存模型到JMM来理解volatile关键字
目录 并发编程三大特性 原子性 可见性 有序性 CPU缓存模型是什么 高速缓存为何出现? 缓存一致性问题 如何解决缓存不一致 JMM内存模型是什么 JMM的规定 Java对三大特性的保证 原子性 可见 ...
- java并发编程(十三)经典问题生产者消费者问题
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据&q ...
- java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)
这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...
- Java并发编程(十三)-- 线程池
什么是线程池? 线程池就是以一个或多个线程循环执行多个应用逻辑的线程集合. 为什么用线程池? 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时 ...
- 【java并发编程】十三章:显式锁:LOCK
java5以后,新增了显式锁,用于当内置锁不能满足需求后可选择的一种高级方案. lock接口的特点 与内置锁一样,他能提供互斥性,内存可见性,可重入等特征,与内置锁不同的是,Lock提供了一种无条件, ...
- Java并发编程(十三)同步容器类
同步容器类 Vector.HashTable,我用的很少:Vecotr的实现和ArrayList挺接近的,不同的是Vector中很多的方法都用synchronized进行了同步.在不强调线程安全地时候 ...
- Java并发编程(十三)在现有的线程安全类中添加功能
重用现有的类而不是创建新的类,可以降低工作量,开发风险以及维护成本. 有时候线程安全类可以支持我们所有的操作,但更多时候,现有的了类只能支持大部分的操作,此时就需要在不破坏线程安全性的情况下添加一个新 ...
随机推荐
- (3)markdown软件的使用
运行Mou.zip解压出来一个软件,它让托到应用程序中,然后打开 另一种软件为gitBook 安装好软件后,使用快捷键F4可以调出所有的应用程序 使用md(markdown简称)有个缺点就是,当内容比 ...
- akoj-1369 贪吃蛇
贪吃蛇 Time Limit:1000MS Memory Limit:65536K Total Submit:9 Accepted:2 Description 有童年的孩子都玩过这个经典游戏,不过这里 ...
- nstallation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED报这个错的原因???
[2015-06-05 20:37:51 - 05ListView列表控件] ------------------------------ [2015-06-05 20:37:51 - 05ListV ...
- 20. Valid Parentheses【leetcode】
20. Valid Parentheses Given a string containing just the characters '(', ')', '{', '}', '[' and ']', ...
- Hadoop1.0.3安装部署
0x00 大数据平台相关链接 官网:http://hadoop.apache.org/ 主要参考教程:http://www.cnblogs.com/xia520pi/archive/2012/05/1 ...
- ASP.NET Core身份验证服务框架IdentityServer4-整体介绍
一.整体情况 现代应用程序看起来更像这个: 最常见的相互作用: 浏览器与Web应用程序的通信 Browser -> Web App Web应用程序与Web API通信 基于浏览器的应用程序与We ...
- Vue过渡效果之CSS过渡
前面的话 Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果.本文将从CSS过渡transition.CSS动画animation及配合使用第三方CSS动画库(如animate. ...
- redux深入理解之中间件(middleware)
理解reduce函数 reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值. arr.reduce([callback, initi ...
- nmake学习笔记2
makefile中的“@<<”看起来很奇怪,查很多地方都没有结果.写了两个示例比较其结果: 如果makefile如下: All:main.obj func.obj link $** .cp ...
- android炫酷动画源码,QQ菜单、瀑布流、二维码源码
Android精选源码 自定义弹框封装,ProgressDialog,StatusDialog和Toast,支持自定义颜色 有深度感的fragment代码 在屏幕顶部或者底部显示提示 短信转发工具,自 ...