生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue
我的技术博客经常被流氓网站恶意爬取转载。请移步原文:http://www.cnblogs.com/hamhog/p/3555111.html,享受整齐的排版、有效的链接、正确的代码缩进、更好的阅读体验。
【实现1:synchronized】
含测试函数main。
public class ProductManagerUsingSync { static final int MAX_AMOUNT = 1000;
int currentAmount; /**
* @param args
*/
public static void main(String[] args) {
ProductManagerUsingSync manager = new ProductManagerUsingSync(); for (int i = 0; i < 5; i++){
int consume = (int) Math.round(Math.random()*50) + 10;
Thread consumerThread = new Thread(new ConsumerWithSync(consume, manager));
consumerThread.start();
} for (int i = 0; i < 10; i++){
int produce = (int) Math.round(Math.random()*50) + 10;
Thread producerThread = new Thread(new ProducerWithSync(produce, manager));
producerThread.start();
}
} public ProductManagerUsingSync() {
currentAmount = 0;
} /**
* Add product. If can't, return.
* @param addAmount
* @return if succeeded.
*/
public boolean addProduct(int addAmount){
if (currentAmount + addAmount > MAX_AMOUNT)
return false; currentAmount += addAmount;
System.out.println("produced: " + addAmount + " current: " + currentAmount);
return true;
} /**
* Take product. If can't, return.
* @param takeAmount The amount of product to take.
* @return if succeeded.
*/
public boolean takeProduct(int takeAmount){
if (takeAmount > currentAmount)
return false; currentAmount -= takeAmount;
System.out.println("consumed: " + takeAmount + " current: " + currentAmount);
return true;
} } class ProducerWithSync implements Runnable {
private int amount;
private ProductManagerUsingSync manager; ProducerWithSync(int amount, ProductManagerUsingSync manager) {
this.amount = amount;
this.manager = manager;
} @Override
public void run() {
while (true) {
synchronized (manager) {
if (manager.addProduct(amount))
return;
}
}
}
} class ConsumerWithSync implements Runnable {
private int amount;
private ProductManagerUsingSync manager; ConsumerWithSync(int amount, ProductManagerUsingSync manager) {
this.amount = amount;
this.manager = manager;
} @Override
public void run() {
while (true) {
synchronized (manager) {
if (manager.takeProduct(amount))
return;
}
}
}
}
解释:Consumer类和Producer类在run方法中进行产品的生产和消费。重点在于:1. 在尝试生产、消费前会获取manager上的锁。由于所有的生产者、消费者中的manager都是同一个实例,因此消费、生产过程是保证线程安全(单线程串行)的。2. 在生产、消费失败的情况下,会进入死循环,反复再次尝试,直到成功为止。
这种实现方法下,暂时不能生产、消费时需要一直死循环,太占资源了;如果在每次循环之间sleep,则不一定能及时生产、消费。
【实现2:signal/notifyAll】
含测试函数main。
public class ProductManagerUsingSignal { static final int MAX_AMOUNT = 1000;
int currentAmount; /**
* @param args useless
*/
public static void main(String[] args) {
ProductManagerUsingSignal manager = new ProductManagerUsingSignal(); for (int i = 0; i < 5; i++){
int consume = (int) Math.round(Math.random()*50);
Thread consumerThread = new Thread(new Consumer(consume, manager));
consumerThread.start();
} for (int i = 0; i < 10; i++){
int produce = (int) Math.round(Math.random()*50);
Thread producerThread = new Thread(new Producer(produce, manager));
producerThread.start();
}
} public ProductManagerUsingSignal(){
currentAmount = 0;
} /**
* Add product. If can't, wait. NotifyAll when finished.
* @param addAmount The amount of product to add.
*/
public synchronized void addProduct(int addAmount){
while (currentAmount + addAmount > MAX_AMOUNT) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
currentAmount += addAmount;
System.out.println("produced: " + addAmount + " current: " + currentAmount);
notifyAll();
} /**
* Take product. If can't, wait. NotifyAll when finished.
* @param takeAmount The amount of product to take.
*/
public synchronized void takeProduct(int takeAmount){
while (takeAmount > currentAmount) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
currentAmount -= takeAmount;
System.out.println("consumed: " + takeAmount + " current: " + currentAmount);
notifyAll();
} } class Producer implements Runnable {
private int amount;
private ProductManagerUsingSignal manager; Producer(int amount, ProductManagerUsingSignal manager) {
this.amount = amount;
this.manager = manager;
} @Override
public void run() {
manager.addProduct(amount);
}
} class Consumer implements Runnable {
private int amount;
private ProductManagerUsingSignal manager; Consumer(int amount, ProductManagerUsingSignal manager) {
this.amount = amount;
this.manager = manager;
} @Override
public void run() {
manager.takeProduct(amount);
}
}
解释:这种实现同样用synchronized保证线程安全;它的重点在于,当生产、消费失败时,会进入wait状态,让位给其他线程;而完成一次成功的生产或消费后,会调用notifyAll方法,唤醒之前等待状态的进程。这种实现在效率上要好于第一种。
【实现3:BlockingQueue】
含测试函数main。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; public class ProductManagerUsingBlockingQueue { BlockingQueue<Integer> sharedQueue;
/**
* @param args
*/
public static void main(String[] args) {
sharedQueue = new LinkedBlockingQueue<Integer>(); for (int i = 0; i < 10; i++){
Thread consumerThread = new Thread(new ConsumerWithBlockingQueue(sharedQueue));
consumerThread.start();
} for (int i = 0; i < 10; i++){
Thread producerThread = new Thread(new ProducerWithBlockingQueue(i, sharedQueue));
producerThread.start();
}
} } class ProducerWithBlockingQueue implements Runnable { private int amount;
private final BlockingQueue<Integer> sharedQueue; public ProducerWithBlockingQueue (int amount, BlockingQueue<Integer> sharedQueue) {
this.amount = amount;
this.sharedQueue = sharedQueue;
} @Override
public void run() { try {
sharedQueue.put(amount);
System.out.println("produced: " + amount);
} catch (InterruptedException e) {
e.printStackTrace();
}
} } class ConsumerWithBlockingQueue implements Runnable{ private final BlockingQueue<Integer> sharedQueue; public ConsumerWithBlockingQueue (BlockingQueue<Integer> sharedQueue) {
this.sharedQueue = sharedQueue;
} @Override
public void run() {
try {
System.out.println("consumed: " + sharedQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
解释:这种方法借助数据结构BlockingQueue(初始化好像应该放在构造函数里,暂时来不及改了),底层原理与signal/notifyAll类似,但代码实现就简洁了许多。
【总结】
在需要实现生产者-消费者模式的场景下,我们可以优先考虑用BlockingQueue来实现。
生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue的更多相关文章
- java多线程:线程间通信——生产者消费者模型
一.背景 && 定义 多线程环境下,只要有并发问题,就要保证数据的安全性,一般指的是通过 synchronized 来进行同步. 另一个问题是,多个线程之间如何协作呢? 我们看一个仓库 ...
- 结合生活,剖析《生产者消费者模型》-java多线程(一)
博客园的园友们好,看博客园上各位大佬的文章,已陪伴了我程序员职业的三年, 如今自己同样希望能把自己从小白到菜鸟的成长过程分享给大家.不定期更新!!! 首先我本人智商不高,理解问题十分吃力,完全不属于天 ...
- 【1】【JUC】Condition和生产者消费者模型
本篇文章将介绍Condition的实现原理和基本使用方法,基本过程如下: 1.Condition提供了await()方法将当前线程阻塞,并提供signal()方法支持另外一个线程将已经阻塞的线程唤醒. ...
- Java里的生产者-消费者模型(Producer and Consumer Pattern in Java)
生产者-消费者模型是多线程问题里面的经典问题,也是面试的常见问题.有如下几个常见的实现方法: 1. wait()/notify() 2. lock & condition 3. Blockin ...
- Java多线程15:Queue、BlockingQueue以及利用BlockingQueue实现生产者/消费者模型
Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...
- Java 实现生产者 – 消费者模型
转自:http://www.importnew.com/27063.html 考查Java的并发编程时,手写“生产者-消费者模型”是一个经典问题.有如下几个考点: 对Java并发模型的理解 对Java ...
- 生产者消费者模型Java实现
生产者消费者模型 生产者消费者模型可以描述为: ①生产者持续生产,直到仓库放满产品,则停止生产进入等待状态:仓库不满后继续生产: ②消费者持续消费,直到仓库空,则停止消费进入等待状态:仓库不空后,继续 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- Java多线程14:生产者/消费者模型
什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...
随机推荐
- PowerDesigner 正向工程 和 逆向工程 说明
PowerDesigner 正向工程 和 逆向工程 说明 database数据库脚本oraclegenerationsql 目录(?)[+] 一. 正向工程与逆向工程说明 在前面几篇里介绍了几 ...
- Using breakpad in cocos2d-x 3.2,dump信息收集
作者:HU 转载请注明,原文链接:http://www.cnblogs.com/xioapingguo/p/4037268.html 一.基本步骤 1.生成转换工具 2.把breakpad加入到项目 ...
- mysql学习--mysql必知必会1
例如以下为mysql必知必会第九章開始: 正則表達式用于匹配特殊的字符集合.mysql通过where子句对正則表達式提供初步的支持. keywordregexp用来表示后面跟的东西作为正則表達式 ...
- 【转】简明vim练级攻略
本文来自:http://coolshell.cn/articles/5426.html vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一 ...
- Python 调用C++
1.C++代码提供Python需要的接口: #include "stdafx.h" #include <boost/python.hpp> #include <s ...
- BZOJ 1090: [SCOI2003]字符串折叠 区间DP
1090: [SCOI2003]字符串折叠 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...
- 飘逸的python - 理解打开文件的模式
当我们用open()函数去打开文件的时候,有好几种打开的模式. 'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'->二 ...
- jquery html标签的链式语法
<div id="ProductNet"> <table border='0' cellspacing='2' cellpadding='0' style='te ...
- log_slave_updates在线修改
http://planet.mysql.com/entry/?id=20450 mysql> show variables like 'log_slave_updates'; +-------- ...
- Mysql一些重要配置参数的学习与整理系列
http://my.oschina.net/realfighter/blog?catalog=585558&temp=1467909771588