java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现
java多线程15 :wait()和notify() 的生产者/消费者模式
利用await()/signal()实现生产者和消费者模型
一样,先定义一个缓冲区:
public class ValueObject
{
public static String value = "";
}
换种写法,生产和消费方法放在一个类里面:
public class ThreadDomain41 extends ReentrantLock
{
private Condition condition = newCondition(); public void set()
{
try
{
lock();
while (!"".equals(ValueObject.value))
condition.await();
ValueObject.value = "123";
System.out.println(Thread.currentThread().getName() + "生产了value, value的当前值是" + ValueObject.value);
condition.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
unlock();
}
} public void get()
{
try
{
lock();
while ("".equals(ValueObject.value))
condition.await();
ValueObject.value = "";
System.out.println(Thread.currentThread().getName() + "消费了value, value的当前值是" + ValueObject.value);
condition.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
unlock();
}
}
}
同样的,开两个线程,一个线程调用set()方法生产,另一个线程调用get()方法消费:
public static void main(String[] args)
{
final ThreadDomain41 td = new ThreadDomain41();
Runnable producerRunnable = new Runnable()
{
public void run()
{
for (int i = 0; i < Integer.MAX_VALUE; i++)
td.set();
}
};
Runnable customerRunnable = new Runnable()
{
public void run()
{
for (int i = 0; i < Integer.MAX_VALUE; i++)
td.get();
}
};
Thread ProducerThread = new Thread(producerRunnable);
ProducerThread.setName("Producer");
Thread ConsumerThread = new Thread(customerRunnable);
ConsumerThread.setName("Consumer");
ProducerThread.start();
ConsumerThread.start();
}
看一下运行结果:
...
Producer生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer生产了value, value的当前值是123
Consumer消费了value, value的当前值是
...
和wait()/notify()机制的实现效果一样,同样符合生产者/消费者模型
小心假死
生产者/消费者模型最终达到的目的是平衡生产者和消费者的处理能力,达到这个目的的过程中,并不要求只有一个生产者和一个消费者。可以多个生产者对应多个消费者,可以一个生产者对应一个消费者,可以多个生产者对应一个消费者。
假死就发生在上面三种场景下。理论分析就能说明问题,所以就不写代码了。代码要写也很简单,上面的两个例子随便修改一个,开一个生产者线程/多个消费者线程、开多个生产者线程/消费者线程、开多个生产者线程/多个消费者线程都可以。假死指的是全部线程都进入了WAITING状态,那么程序就不再执行任何业务功能了,整个项目呈现停滞状态。
比方说有生产者A和生产者B,缓冲区由于空了,消费者处于WAITING。生产者B处于WAITING,生产者A被消费者通知生产,生产者A生产出来的产品本应该通知消费者,结果通知了生产者B,生产者B被唤醒,发现缓冲区满了,于是继续WAITING。至此,两个生产者线程处于WAITING,消费者处于WAITING,系统假死。
上面的分析可以看出,假死出现的原因是因为notify的是同类,所以非单生产者/单消费者的场景,可以采取两种方法解决这个问题:
1、synchronized用notifyAll()唤醒所有线程、ReentrantLock用signalAll()唤醒所有线程
2、用ReentrantLock定义两个Condition,一个表示生产者的Condition,一个表示消费者的Condition,唤醒的时候调用相应的Condition的signal()方法就可以了
这里对比 和 wait/notify ,await()/signal() 可以利用多个Condition 进行消费/生产实现效果,不用通知所有线程,这里显得更加效率,方便
java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现的更多相关文章
- Java多线程_生产者消费者模式2
在我的上一条博客中,已经介绍到了多线程的经典案列——生产者消费者模式,但是在上篇中用的是传统的麻烦的非阻塞队列实现的.在这篇博客中我将介绍另一种方式就是:用阻塞队列完成生产者消费者模式,可以使用多种阻 ...
- Java多线程-----实现生产者消费者模式的几种方式
1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理 ...
- 【多线程】java多线程实现生产者消费者模式
思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...
- JAVA多线程之生产者 消费者模式 妈妈做面包案例
创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包 最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...
- Java多线程编程——生产者-消费者模式(1)
生产者-消费者模式在生活中非常常见.就拿我们去餐馆吃饭为例.我们会遇到以下两种情况: 1.厨师-客人 如下图所示,生产者.消费者直接进行交互. 生产者生产出产品后,通知消费者:消费者消费后,通知生产者 ...
- Java多线程_生产者消费者模式1
生产者消费者模型 具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式如下图.(图片来自网络 ...
- java多线程解决生产者消费者问题
import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...
- 【多线程】--生产者消费者模式--Lock版本
在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...
- Java设计模式之生产者消费者模式
Java设计模式之生产者消费者模式 博客分类: 设计模式 设计模式Java多线程编程thread 转载 对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一 ...
随机推荐
- jQuery UI API - 可拖拽小部件(Draggable Widget)(转)
所属类别 交互(Interactions) 用法 描述:允许使用鼠标移动元素. 版本新增:1.0 依赖: UI 核心(UI Core) 部件库(Widget Factory) 鼠标交互(Mouse I ...
- C#多线程JOIN方法初探
[说明:刚接触多线程时,弄不明白Join()的作用,查阅了三本书,都不明不白.后来经过自己的一番试验,终于弄清了Join()的本质.大家看看我这种写法是否易懂,是否真的写出了Join()的本质,多提宝 ...
- FaceBook登陆API -- Login with API calls
Login with API calls Related Topics Understanding sessions FBSession Error handling FBError FBLoginC ...
- 第3章 Python基础-文件操作&函数 文件操作 练习题
一.利用b模式,编写一个cp工具,要求如下: 1. 既可以拷贝文本又可以拷贝视频,图片等文件 2. 用户一旦参数错误,打印命令的正确使用方法,如usage: cp source_file target ...
- Eclipse安装PlantUML插件
新技术的诞生和更新,新工具的发现和使用是两件让人开心的事情. 还记得Visio下苦苦的画流程图的时光吗,现在一切都变得so easy,因为有PlantUML! 官网:http://plantuml.c ...
- Python 爬虫实例(11)—— 爬虫 苏宁易购
# coding:utf-8 import json import redis import time import requests session = requests.session() imp ...
- Linux 下的hiredis的简单安装、测试*(转)
上一章介绍的是如何安装Redis以及在Redis客户端上进行简单测试,但是我们一般安装完Redis之后,都是要结合编程语言对其进行应用的,hiredis是redis开源库对外发布的客户端API包,这一 ...
- Hibernate 连接访问多个数据库(含访问不同数据库的相同表)(转)
利用hibernate访问不同数据库中的不同表或不同数据库中的相同表. 本人在开发过程中的解决方案,希望大家交流.一般用myEclipse工具会自动生成Hibernate的相关文件,大致有下面几类: ...
- 使用 sqlyog 导入导出数据显示 lost connection to mysql server during query
mysql中经常需要备份数据,在使用 sqlyog 进行备份数据库为转储文件,然后在其他数据库中导入发生 lost connection 经过查询大量资料是数据库配置的 max_allowed_pac ...
- unity, ugui toggle, dynamic bool
假设Canvas_debugControl.cs有一个函数 public void showNextSceneButton(bool value){ ... } 欲将其添加到一个ugui toggle ...