问题在《一个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.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(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(); } } }
在回答里还一个类似的,不过还是不太一样。
http://blog.csdn.net/liguogangde/article/details/9103501
相关推荐
a: 创建一个线程 ...h: problem1 生产者消费者问题 (1生产者 1消费者 1缓冲区) problem1 more 生产者消费者问题 (1生产者 2消费者 4缓冲区) problem2 读者与写着问题 I: 信号量 semaphore 解决线程同步问题
在多线程编程中,"生产者-消费者"模型是一个经典的并发问题,它涉及到了如何在多个线程间共享资源并协同工作。本示例是使用C++实现的一个解决方案,结合了Posix信号量和互斥量来确保线程安全和同步。 生产者-消费者...
第一行说明程序中设置几个临界区,其余每行分别描述了一个生产者或者消费者线程的信息。每一行的各字段间用Tab键隔开。不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。第二个字段用字母...
在计算机科学中,生产者消费者问题是一个经典的问题,它描述了多个生产者和消费者共享一个缓冲区的情形。在这个问题中,多个生产者将产品放入缓冲区中,而多个消费者则从缓冲区中取出产品。如果缓冲区为空,消费者将...
本资源“解决线程死锁问题的 生产者 消费者程序.rar”显然是针对这一问题提供的一种解决方案,它特别关注了Linux环境下的线程管理。"生产者-消费者"模型是一个经典的并发编程模型,用于演示如何有效地共享有限资源,...
生产者-消费者问题是一个经典的多线程同步问题,在计算机科学领域中,主要用于研究如何在多个线程之间进行协调工作的问题。该实验旨在通过编程实现生产者与消费者的逻辑,了解进程间的互斥访问机制以及临界区的概念...
通过上述分析可以看出,该程序有效地解决了生产者消费者问题中的同步与互斥问题。使用信号量作为同步工具,不仅简化了代码逻辑,还提高了程序的并发性能。这种解决方案对于理解多线程编程及同步机制具有重要的意义。
以下是一段简单的生产者消费者模式的代码示例: ```java import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumerExample { public static...
在操作系统设计中,生产者-消费者问题是一个经典的同步问题,它描述了两个或多个进程(生产者和消费者)如何共享一个有限的...通过分析和调试这段代码,我们可以更直观地感受生产者-消费者模式在解决同步问题上的应用。
生产者消费者问题是多线程编程中的经典问题,描述了两个线程角色:生产者负责生成数据,消费者负责消耗数据。在共享数据结构(如缓冲区)中,生产者不能直接将数据推送给消费者,而消费者也不能在缓冲区为空时尝试...
本文将详细介绍如何通过编程方式解决生产者消费者问题,这是一个经典的多线程同步问题。在本例中,我们将采用C++语言结合Windows API来实现。该示例程序展示了如何在同一个进程地址空间内,让多个线程(生产者线程与...
通过分析和理解这段代码,我们可以更好地掌握多线程编程和并发控制的概念,这对于理解和优化多线程应用程序至关重要。同时,这也是操作系统课程中的一个重要实践环节,帮助学生理论联系实际,提升解决实际问题的能力...
在计算机科学中,生产者消费者问题是多线程编程中的一个经典问题,主要涉及线程间的同步与通信。在这个问题中,生产者线程负责生成数据,而消费者线程则负责消费这些数据。为了保证数据的一致性和避免资源冲突,我们...
2. 生产者-消费者问题:线程间共享数据时,生产者线程生产和消费者线程消费需协调。可以使用队列和信号量解决。 3. 线程安全:确保多线程访问共享资源时不会出错。使用原子操作、线程局部存储、不可变对象等方式增强...
在IT领域,多线程是一种常见的编程模型,用于提高程序的执行效率,特别是在并发和并行处理场景下。本文将详细解析"多线程代码实例",主要关注在Linux环境中,使用C语言实现的生产消费管理系统,以及如何利用POSIX...
在计算机科学领域,"生产者-消费者"问题是一个经典的多线程同步问题,它涉及到并发编程中的资源管理和数据共享。该问题描述了两个角色:生产者(Producer)和消费者(Consumer),他们共同操作一个有限容量的缓冲区...
总结来说,Windows多线程环境下的生产者-消费者模型通过关键代码段和互斥量实现线程同步,有效地解决了并发访问共享资源的问题。关键代码段适用于同一进程内的线程同步,而互斥量则可跨越进程边界,保证全局资源的...
多线程应用程序设计 多线程应用程序设计是指在一个进程中运行多个线程,每个线程共享进程的资源,包括打开的文件、页表、信号标识及动态分配的内存...但是,多线程程序的编写也需要注意线程间通讯和数据共享的问题。