作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列。所以只谈论问题本身,不谈论好不好。

具体代码:

  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. //生产/消费者模式
  5. public class Basket {
  6. Lock lock = new ReentrantLock();
  7. // 产生Condition对象
  8. Condition produced = lock.newCondition();
  9. Condition consumed = lock.newCondition();
  10. boolean available = false;
  11. public void produce() throws InterruptedException {
  12. lock.lock();
  13. try {
  14. if (available) {
  15. produced.await(); // 放弃lock进入睡眠
  16. }
  17. System.out.println("Apple produced.");
  18. available = true;
  19. consumed.signal(); // 发信号唤醒等待这个Condition的线程
  20. } finally {
  21. lock.unlock();
  22. }
  23. }
  24. public void consume() throws InterruptedException {
  25. lock.lock();
  26. try {
  27. if (!available) {
  28. consumed.await(); // 放弃lock进入睡眠
  29. }
  30. /* 吃苹果 */
  31. System.out.println("Apple consumed.");
  32. available = false;
  33. produced.signal(); // 发信号唤醒等待这个Condition的线程
  34. } finally {
  35. lock.unlock();
  36. }
  37. }
  38. }
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();

        }

    }

}
  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;
  3. //测试用类
  4. public class ConditionTester {
  5. public static void main(String[] args) throws InterruptedException {
  6. final Basket basket = new Basket();
  7. // 定义一个producer
  8. Runnable producer = new Runnable() {
  9. public void run() {
  10. try {
  11. basket.produce();
  12. } catch (InterruptedException ex) {
  13. ex.printStackTrace();
  14. }
  15. }
  16. };
  17. // 定义一个consumer
  18. Runnable consumer = new Runnable() {
  19. public void run() {
  20. try {
  21. basket.consume();
  22. } catch (InterruptedException ex) {
  23. ex.printStackTrace();
  24. }
  25. }
  26. };
  27. // 各产生10个consumer和producer
  28. ExecutorService service = Executors.newCachedThreadPool();
  29. for (int i = ; i < ; i++)
  30. service.submit(consumer);
  31. Thread.sleep( * );
  32. for (int i = ; i < ; i++)
  33. service.submit(producer);
  34. service.shutdown();
  35. }
  36. }
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进入睡眠

}

  1. package com.sishuok.es.test;
  2. import java.util.concurrent.atomic.AtomicInteger;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. //生产/消费者模式
  7. public class Basket {
  8. Lock lock = new ReentrantLock(true);
  9. // 产生Condition对象
  10. Condition produced = lock.newCondition();
  11. Condition consumed = lock.newCondition();
  12. boolean available = false;
  13. AtomicInteger producedAwaitCounter = new AtomicInteger();
  14. public void produce() throws InterruptedException {
  15. lock.lock();
  16. try {
  17. if (available || producedAwaitCounter.get() > ) {
  18. producedAwaitCounter.incrementAndGet();
  19. produced.await(); // 放弃lock进入睡眠
  20. producedAwaitCounter.decrementAndGet();
  21. }
  22. System.out.println("Apple produced.");
  23. available = true;
  24. consumed.signal(); // 发信号唤醒等待这个Condition的线程
  25. } finally {
  26. lock.unlock();
  27. }
  28. }
  29. public void consume() throws InterruptedException {
  30. lock.lock();
  31. try {
  32. if (!available) {
  33. consumed.await(); // 放弃lock进入睡眠
  34. }
  35. /* 吃苹果 */
  36. System.out.println("Apple consumed.");
  37. available = false;
  38. produced.signal(); // 发信号唤醒等待这个Condition的线程
  39. } finally {
  40. lock.unlock();
  41. }
  42. }
  43. }
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生产者消费者问题代码分析的更多相关文章

  1. 基于Java 生产者消费者模式(详细分析)

    Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...

  2. Java 生产者消费者模式详细分析

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  3. Java生产者消费者的三种实现

    Java生产者消费者是最基础的线程同步问题,java岗面试中还是很容易遇到的,之前没写过多线程的代码,面试中被问到很尬啊,面完回来恶补下.在网上查到大概有5种生产者消费者的写法,分别如下. 用sync ...

  4. Java 学习笔记 使用并发包ReentrantLock简化生产者消费者模式代码

    说明 ReentrantLock是java官方的一个线程锁类,ReentarntLock实现了Lock的接口 我们只需要使用这个,就可以不用使用synchronized同步关键字以及对应的notify ...

  5. java 生产者消费者问题 并发问题的解决

    引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...

  6. JAVA生产者消费者的实现

    春节回了趟老家,又体验了一次流水席,由于桌席多,导致上菜慢,于是在等待间,总结了一下出菜流程的几个特点: 1.有多个灶台,多个灶台都在同时做菜出来. 2.做出来的菜,会有专人用一个托盘端出来,每次端出 ...

  7. Java生产者消费者模型

    在Java中线程同步的经典案例,不同线程对同一个对象同时进行多线程操作,为了保持线程安全,数据结果要是我们期望的结果. 生产者-消费者模型可以很好的解释这个现象:对于公共数据data,初始值为0,多个 ...

  8. java 生产者消费者问题 并发问题的解决(转)

    引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...

  9. Linux 进程间通信(包含一个经典的生产者消费者实例代码)

    前言:编写多进程程序时,有时不可避免的需要在多个进程之间传递数据,我们知道,进程的用户的地址空间是独立,父进程中对数据的修改并不会反映到子进程中,但内核是共享的,大多数进程间通信方式都是在内核中建立一 ...

随机推荐

  1. python数值计算模块NumPy scipy安装

    NumPy为Python提供了快速的多维数组处理的能力,而SciPy则在NumPy基础上添加了众多的科学计算所需的各种工具包,有了这两个库,Python就有几乎和Matlab一样的处理数据和计算的能力 ...

  2. BZOJ 3211 花神游历各国 (树状数组+并查集)

    题解:首先,单点修改求区间和可以用树状数组实现,因为开平方很耗时间,所以在这个方面可以优化,我们知道,开平方开几次之后数字就会等于1 ,所以,用数组记录下一个应该开的数,每次直接跳到下一个不是1的数字 ...

  3. Runtime.exec使用错误导致延迟.md

    这篇文章是纪录了一个bug解决的过程,可是我还是没有可以真正地找出bug的缘由.希望大牛可以详解. 问题的发现 当接触的系统越来越大的时候,对于系统的性能越来越高的时候,找到表面问题的真正原因就慢慢地 ...

  4. HDU 4859(Bestcoder #1 1003)海岸线(网络流之最小割)

    题目地址:HDU4859 做了做杭电多校,知识点会的太少了.还是将重点放在刷专题补知识点上吧,明年的多校才是重点. 这题题目求的最长周长.能够试想一下,这里的海岸线一定是在"."和 ...

  5. 使用C#对MongoDB中的数据进行查询,改动等操作

    首先,使用的是官方提供的C#訪问组件https://github.com/mongodb/mongo-csharp-driver 然后.编译后引用MongoDB.Bson.dll及MongoDB.Dr ...

  6. Orchard 添加搜索栏

    Orchard 提供索引和搜索的功能. 索引功能需要开启 Indexing 模块, 同时我们要开启Lucene 模块(做实际检索工作的东西). 然后还要开启Search模块(调用Lucene 查询然后 ...

  7. 读取jar包里面的文件

    一.最近做项目的时候,师兄要求读取jar包里面的java文件.在网上查了各种文件以后,终于完成了,在这里和各位朋友分享一下. (一)找到jar包所在的位置. String path="XXX ...

  8. linux shell: 搜索字符串,剔除包含特定字符的行

    搜索代码中出现CONFIG_BOOTARGS的行,但又不希望有#define和#undef, 暂时不知带如何直接用一个语句做到,因此用了如下三个语句. find . -type f | xargs g ...

  9. A + B Problem II 大数加法

    题目描述: Input The first line of the input contains an integer T(1<=T<=20) which means the number ...

  10. Python 2.7 学习笔记 中文处理

    首先我们在编写python代码文件时,文件本身会采用一种编码格式,如 utf-8 或 gbk 这时我们需要在python文件的开头设置文件的编码格式,以告诉编译器. 如果文件的编码格式是 utf-8, ...