用Condition条件变量实现生产者消费者模式

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumerPattern{
	public static final int MAX_CAP = 20;
    static LinkedList<Object> list = new LinkedList<Object>();
    static ReentrantLock lock = new ReentrantLock();
    static Condition notFull = lock.newCondition();
    static Condition notEmpty = lock.newCondition();
    
    static class Producer implements Runnable {

		@Override
		public void run() {
			while(true) {
				try {
					lock.lock();
					while(list.size() == MAX_CAP) {
						try {
							System.out.println("当前已有"+list.size()+"个产品,缓冲区已满,请等待消费者消费");
							notFull.await();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					list.add(new Object());
					System.out.println("生产了一个产品,当前产品个数为 " + list.size());
					notEmpty.signalAll();
				} finally {
					lock.unlock();
				}
				Thread.yield();
			}
		}
    }
    
    static class Consumer implements Runnable {

		@Override
		public void run() {
			while(true) {
				try {
					lock.lock();
					while(list.size() == 0) {
						try {
							System.out.println("当前已有"+list.size()+"个产品,缓冲区已空,请等待生产者生产");
							notEmpty.await();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					list.remove();
					try {
						Thread.sleep(700);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("消费了一个产品,当前产品个数为 " + list.size());
					notFull.signalAll();
				} finally {
					lock.unlock();
				}
				Thread.yield();
			}
		}
    }
	public static void main(String[] args) throws InterruptedException {
		for(int i=0; i<3; i++) {
			new Thread(new Producer()).start();
		}
		for(int i=0; i<3; i++) {
			new Thread(new Consumer()).start();
		}
	}
}

部分输出结果如下:

生产了一个产品,当前产品个数为 11
生产了一个产品,当前产品个数为 12
生产了一个产品,当前产品个数为 13
消费了一个产品,当前产品个数为 12
消费了一个产品,当前产品个数为 11
消费了一个产品,当前产品个数为 10
消费了一个产品,当前产品个数为 9
…………………………(省略部分输出)
生产了一个产品,当前产品个数为 16
生产了一个产品,当前产品个数为 17
生产了一个产品,当前产品个数为 18
生产了一个产品,当前产品个数为 19
消费了一个产品,当前产品个数为 18
生产了一个产品,当前产品个数为 19
生产了一个产品,当前产品个数为 20
当前已有20个产品,缓冲区已满,请等待消费者消费
当前已有20个产品,缓冲区已满,请等待消费者消费
消费了一个产品,当前产品个数为 19
消费了一个产品,当前产品个数为 18
消费了一个产品,当前产品个数为 17

 

       总结:用条件变量与用wait和notify/notifyAll实现这个模式有一个不同之处在于,Condition的signalAll方法只能唤醒在某一条件上进行阻塞的线程,比如notEmpty.signalAll()只能唤醒通过notEmpty.await()方法而阻塞的线程,在这个例子中的话也就是说生产者调用notEmpty.signalAll()只能唤醒消费者线程,而notifyAll()会唤醒所有在同一个对象锁(Object monitor)上进行等待的线程,比如说生产者和消费者都会因争夺缓冲区对象的锁而导致阻塞,同时在缓冲区满时生产者会调用wait方法进行阻塞,在缓冲区空时消费者会调用wait方法进行阻塞,一旦有线程(不管是生产者还是消费者)调用了notifyAll()方法,则所有的阻塞在同一个Object monitor上的线程都会被唤醒。也就是说Condition的signalAll()是基于某个条件变量进行唤醒,notifyAll是基于某个对象锁(Object monitor)进行唤醒。

        以上总结纯属个人的体会,可能有误。关于这两种实现方式的详细差别,以后再作深入学习。水平有限,如有不当之处,还望指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生产者消费者问题是一个经典的并发编程问题,可以使用多种编程语言实现。下面是使用 C++ 实现生产者消费者问题的示例代码: ```c++ #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> using namespace std; const int kMaxSize = 10; // 缓冲区最大容量 queue<int> buffer; // 缓冲区 mutex mtx; // 互斥锁,保护缓冲区 condition_variable not_full_cv, not_empty_cv; // 条件变量,用于线程同步 void producer() { for (int i = 1; i <= 20; ++i) { unique_lock<mutex> lock(mtx); not_full_cv.wait(lock, [] { return buffer.size() < kMaxSize; }); // 等待缓冲区未满 buffer.push(i); cout << "producer: " << i << endl; not_empty_cv.notify_all(); // 通知消费者线程缓冲区不为空 } } void consumer() { int data = 0; while (data != 20) { unique_lock<mutex> lock(mtx); not_empty_cv.wait(lock, [] { return !buffer.empty(); }); // 等待缓冲区不为空 data = buffer.front(); buffer.pop(); cout << "consumer: " << data << endl; not_full_cv.notify_all(); // 通知生产者线程缓冲区未满 } } int main() { thread prod(producer); thread cons(consumer); prod.join(); cons.join(); return 0; } ``` 这个程序中,生产者线程不断向缓冲区中生产数据,消费者线程不断从缓冲区中消费数据,直到生产者线程生产完数据并退出。在程序中,使用互斥锁保护了缓冲区,防止多个线程同时访问,使用条件变量实现了线程同步。`not_full_cv` 条件变量用于通知生产者线程缓冲区未满,`not_empty_cv` 条件变量用于通知消费者线程缓冲区不为空。在生产者线程和消费者线程中,使用 `wait` 函数等待条件变量满足,当条件变量满足时再执行相应的操作,并使用 `notify_all` 函数通知其他线程条件变量已经满足,可以继续执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值