生产和消费者模式有很多种,现在介绍几种常见的方式
- wait/notify实现生产和消费者模式
1、使用wait/notify实现生产和消费者模式:
public class Depot { // 实际容量 private volatile int capacity = 0 ; // 最大容量 private static final int MAX_CAPACITY = 100 ; // 锁 private final Object lock = new Object() ; public Depot(){ } /** * 生产 * @param: num * @return: */ public void producer(int num) { if(num<0){ System.out.println("生产数量不可为负数"); throw new IllegalArgumentException("生产数量不可为负数") ; } synchronized (lock){ // 生产 int left = 0; try { left = doProducer(num); // 要求生产数量未达标,让出执行权 while (left > 0){ Thread.yield(); left = doProducer(left); } } catch (InterruptedException e) { e.printStackTrace(); } lock.notify(); } } /** * 实际生产逻辑 * @param: num * @return: 返回未生产数量 */ private int doProducer(int num) throws InterruptedException { // 实际增加数量 int grow = num ; // 未生产数量 int left = 0 ; // 等待仓库被消费 while (capacity>=MAX_CAPACITY){ lock.wait(); } // 计算实际新增数量 if( (num+capacity) > MAX_CAPACITY ){ grow = MAX_CAPACITY - capacity ; left = num - grow ; } capacity += grow ; // 仓库已经生产,通知消费者消费 lock.notify(); System.out.println(Thread.currentThread().getName() + " Plan Producer = " + num + " Actually = " + grow + " left = " + left + " capacity = " + capacity); return left ; } /** * 消费 * @param: num * @return: */ public void consumer(int num) { if(num<0){ System.out.println("消费数量不可为负数"); throw new IllegalArgumentException("消费数量不可为负数") ; } synchronized (lock){ // 消费仓库 int left = 0; try { left = doConsumer(num); // 要求消费数量未达标,让出执行权 while (left > 0){ Thread.yield(); left = doConsumer(left); } } catch (InterruptedException e) { e.printStackTrace(); } // 仓库已经被消费,通知生产者生产 lock.notify(); } } /** * 实际消费逻辑 * @param: num * @return: 剩余未消费数量 */ private int doConsumer(int num) throws InterruptedException { // 实际消费数量 int decrease = num ; // 剩余未消费 int left = 0 ; // 等待仓库生产 while (capacity <= 0){ lock.wait(); } // 计算实际消费数量 if(decrease > capacity){ decrease = capacity ; left = decrease - capacity ; } capacity -= decrease ; System.out.println(Thread.currentThread().getName() + " Plan Consumer = "+ num + " Actually = " + decrease + " left = " + left + " capacity = " + capacity ); return left ; } }
测试案例:
public class ProducerAndConsumer { public static void main(String[] args) throws InterruptedException { Depot depot = new Depot() ; for(int x=0 ; x<4; x++){ new Thread(new Runnable() { @Override public void run() { depot.producer(40); } }).start(); } Thread.sleep(2000L); for(int x=0 ; x<3; x++){ new Thread(new Runnable() { @Override public void run() { depot.consumer(40); } }).start(); } Thread.sleep(2000L); } }
运行结果:
Thread-0 Plan Producer = 40 Actually = 40 left = 0 capacity = 40
Thread-1 Plan Producer = 40 Actually = 40 left = 0 capacity = 80
Thread-2 Plan Producer = 40 Actually = 20 left = 20 capacity = 100
Thread-4 Plan Consumer = 40 Actually = 40 left = 0 capacity = 60
Thread-2 Plan Producer = 20 Actually = 20 left = 0 capacity = 80
Thread-3 Plan Producer = 40 Actually = 20 left = 20 capacity = 100
Thread-6 Plan Consumer = 40 Actually = 40 left = 0 capacity = 60
Thread-5 Plan Consumer = 40 Actually = 40 left = 0 capacity = 20
Thread-3 Plan Producer = 20 Actually = 20 left = 0 capacity = 40
其他待续.........