java生产者消费者问题代码分析
作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列。所以只谈论问题本身,不谈论好不好。
具体代码:
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- //生产/消费者模式
- public class Basket {
- Lock lock = new ReentrantLock();
- // 产生Condition对象
- Condition produced = lock.newCondition();
- Condition consumed = lock.newCondition();
- boolean available = false;
- public void produce() throws InterruptedException {
- lock.lock();
- try {
- if (available) {
- produced.await(); // 放弃lock进入睡眠
- }
- System.out.println("Apple produced.");
- available = true;
- consumed.signal(); // 发信号唤醒等待这个Condition的线程
- } finally {
- lock.unlock();
- }
- }
- public void consume() throws InterruptedException {
- lock.lock();
- try {
- if (!available) {
- consumed.await(); // 放弃lock进入睡眠
- }
- /* 吃苹果 */
- System.out.println("Apple consumed.");
- available = false;
- produced.signal(); // 发信号唤醒等待这个Condition的线程
- } finally {
- lock.unlock();
- }
- }
- }
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //生产/消费者模式 public class Basket { Lock lock = new ReentrantLock(); // 产生Condition对象 Condition produced = lock.newCondition(); Condition consumed = lock.newCondition(); boolean available = false; public void produce() throws InterruptedException { lock.lock(); try { if (available) { produced.await(); // 放弃lock进入睡眠 } System.out.println("Apple produced."); available = true; consumed.signal(); // 发信号唤醒等待这个Condition的线程 } finally { lock.unlock(); } } public void consume() throws InterruptedException { lock.lock(); try { if (!available) { consumed.await(); // 放弃lock进入睡眠 } /* 吃苹果 */ System.out.println("Apple consumed."); available = false; produced.signal(); // 发信号唤醒等待这个Condition的线程 } finally { lock.unlock(); } } }
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- //测试用类
- public class ConditionTester {
- public static void main(String[] args) throws InterruptedException {
- final Basket basket = new Basket();
- // 定义一个producer
- Runnable producer = new Runnable() {
- public void run() {
- try {
- basket.produce();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- };
- // 定义一个consumer
- Runnable consumer = new Runnable() {
- public void run() {
- try {
- basket.consume();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- };
- // 各产生10个consumer和producer
- ExecutorService service = Executors.newCachedThreadPool();
- for (int i = ; i < ; i++)
- service.submit(consumer);
- Thread.sleep( * );
- for (int i = ; i < ; i++)
- service.submit(producer);
- service.shutdown();
- }
- }
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; //测试用类
public class ConditionTester { public static void main(String[] args) throws InterruptedException {
final Basket basket = new Basket(); // 定义一个producer
Runnable producer = new Runnable() {
public void run() {
try {
basket.produce();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}; // 定义一个consumer
Runnable consumer = new Runnable() {
public void run() {
try {
basket.consume();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}; // 各产生10个consumer和producer
ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 4; i++)
service.submit(consumer); Thread.sleep(2000 * 2); for (int i = 0; i < 4; i++)
service.submit(producer); service.shutdown();
}
}
原因分析:
1、假设前面有2个producer(此时available=true)
1.1、一个在等待lock
1.2、一个await
2、consumer生成内容后,available=false,produced.signal(); 最后lock.unlock();
3.1、因为lock.unlock所以会触发一个lock获取到锁(虽然signal也会触发等待这个条件的其他线程,但是多线程大家都知道什么时候触发这是不确定的),如果此时正好是[1.1]那么因为available=false,执行完释放锁
3.2、produced.signal()所以会触发一个await的producer;
解决方案:
只要保证[3.1]还是需要await即可解决问题
所以加一个 AtomicInteger producedAwaitCounter = new AtomicInteger(0); 统计当前等待的生产者,如果当前available=false,但已经有生产者生成了内容,那么先等待消费者消费了再说
if (available || producedAwaitCounter.get() > 0) {
producedAwaitCounter.incrementAndGet();
produced.await(); // 放弃lock进入睡眠
producedAwaitCounter.decrementAndGet();
}
当然最简单的是使用:自旋,原理可以自己分析下:
while (available) {
produced.await(); // 放弃lock进入睡眠
}
- package com.sishuok.es.test;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- //生产/消费者模式
- public class Basket {
- Lock lock = new ReentrantLock(true);
- // 产生Condition对象
- Condition produced = lock.newCondition();
- Condition consumed = lock.newCondition();
- boolean available = false;
- AtomicInteger producedAwaitCounter = new AtomicInteger();
- public void produce() throws InterruptedException {
- lock.lock();
- try {
- if (available || producedAwaitCounter.get() > ) {
- producedAwaitCounter.incrementAndGet();
- produced.await(); // 放弃lock进入睡眠
- producedAwaitCounter.decrementAndGet();
- }
- System.out.println("Apple produced.");
- available = true;
- consumed.signal(); // 发信号唤醒等待这个Condition的线程
- } finally {
- lock.unlock();
- }
- }
- public void consume() throws InterruptedException {
- lock.lock();
- try {
- if (!available) {
- consumed.await(); // 放弃lock进入睡眠
- }
- /* 吃苹果 */
- System.out.println("Apple consumed.");
- available = false;
- produced.signal(); // 发信号唤醒等待这个Condition的线程
- } finally {
- lock.unlock();
- }
- }
- }
package com.sishuok.es.test; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //生产/消费者模式 public class Basket { Lock lock = new ReentrantLock(true); // 产生Condition对象 Condition produced = lock.newCondition(); Condition consumed = lock.newCondition(); boolean available = false;
AtomicInteger producedAwaitCounter = new AtomicInteger(0); public void produce() throws InterruptedException { lock.lock(); try { if (available || producedAwaitCounter.get() > 0) {
producedAwaitCounter.incrementAndGet();
produced.await(); // 放弃lock进入睡眠
producedAwaitCounter.decrementAndGet();
} System.out.println("Apple produced."); available = true; consumed.signal(); // 发信号唤醒等待这个Condition的线程 } finally {
lock.unlock();
} } public void consume() throws InterruptedException { lock.lock(); try { if (!available) {
consumed.await(); // 放弃lock进入睡眠
} /* 吃苹果 */ System.out.println("Apple consumed."); available = false; produced.signal(); // 发信号唤醒等待这个Condition的线程
} finally {
lock.unlock();
} } }
java生产者消费者问题代码分析的更多相关文章
- 基于Java 生产者消费者模式(详细分析)
Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...
- Java 生产者消费者模式详细分析
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- Java生产者消费者的三种实现
Java生产者消费者是最基础的线程同步问题,java岗面试中还是很容易遇到的,之前没写过多线程的代码,面试中被问到很尬啊,面完回来恶补下.在网上查到大概有5种生产者消费者的写法,分别如下. 用sync ...
- Java 学习笔记 使用并发包ReentrantLock简化生产者消费者模式代码
说明 ReentrantLock是java官方的一个线程锁类,ReentarntLock实现了Lock的接口 我们只需要使用这个,就可以不用使用synchronized同步关键字以及对应的notify ...
- java 生产者消费者问题 并发问题的解决
引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...
- JAVA生产者消费者的实现
春节回了趟老家,又体验了一次流水席,由于桌席多,导致上菜慢,于是在等待间,总结了一下出菜流程的几个特点: 1.有多个灶台,多个灶台都在同时做菜出来. 2.做出来的菜,会有专人用一个托盘端出来,每次端出 ...
- Java生产者消费者模型
在Java中线程同步的经典案例,不同线程对同一个对象同时进行多线程操作,为了保持线程安全,数据结果要是我们期望的结果. 生产者-消费者模型可以很好的解释这个现象:对于公共数据data,初始值为0,多个 ...
- java 生产者消费者问题 并发问题的解决(转)
引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...
- Linux 进程间通信(包含一个经典的生产者消费者实例代码)
前言:编写多进程程序时,有时不可避免的需要在多个进程之间传递数据,我们知道,进程的用户的地址空间是独立,父进程中对数据的修改并不会反映到子进程中,但内核是共享的,大多数进程间通信方式都是在内核中建立一 ...
随机推荐
- 百度云世界里的“七种武器”:PCS、BAE、Site App、ScreenX等
如果说去年百度世界的关键词是“百度新首页”的话,那么今年在研发者人群中,对百度世界最深的印象就是“七种武器”,即在云的世界里,百度为开发者所提供的包括个人云存储.LBS.移动云测试中心等在内的七种工具 ...
- Windows 8.1 IIS 8.5 远程管理 Windows 2008 R2 IIS 7.0
案例: Windows 8.1 x64 IIS 8.5 inetmgr_amd64_v1.1_en-US.msi Windows 2008 R2 x64 IIS 7.0 在Win8.1 通过IIS ...
- Python学习入门基础教程(learning Python)--2.2 Python下的变量基础
变量的基本概念,变量可以这样去理解,变量是一个值,这个值存储在计算机的内存里.以网购为例,您在选购傻商品的时候,是在不同页面里选不同的商品,选好一件点击“放入购物车”,选完了再点击去结帐,这些商品的价 ...
- 【转】Ubuntu下deb包的安装方法
[转]Ubuntu下deb包的安装方法 deb是debian linus的安装格式,跟red hat的rpm非常相似,最基本的安装命令是:dpkg -i file.deb dpkg 是Debian P ...
- string.Format()字符串格式化
Format()基本语法: {索引[,对齐][:格式字符串]} ·索引:表示引用的对象列表中的第n个对象参数. ·对齐(可选):设置宽度与对齐方式,该参数为带符号的整数.正数为 ...
- iOS开发针对SQL语句的封装
1.使用依赖关系 a.需要添加libsqlite3.tbd 静态库. b.需要添加第三方框架 FMBD.MJExtension. 2. SQL语句类封装名DataBaseSqlTool 类方法介绍 ...
- Arduino101 中使用 Mirf 库的问题(2016-04-04)
Mirf 库在使用 NRF24L01 的时候接触到,感觉很好用.但在用 Arduino101 的时候遇到一些问题,记录一下,对于底层不了解,希望有熟悉的同学能给点指点: 编译会提示 MirfHardw ...
- 使用phpQuery实现批量文件处理
能够将置顶文夹下的指定类型文件进行处理 <?php header('Content-Type:text/html;Charset=utf-8'); include './phpQuery/php ...
- NSData 数据转换
NSData,数据,当我们需要把一些信息写入到文件里或发送到网络上,我们需要把这些数据转换下,变成纯粹的0.1字符流 数组转 NSData NSData *GLYtime = [NSKeyedArch ...
- open和fopen的区别:
1.缓冲文件系统缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”, 装满后再从内存“缓冲区”依此读入接收的变量.执行 ...