关于生产者与消费者模式的两种实现方式
Posted hunter_Cecil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于生产者与消费者模式的两种实现方式相关的知识,希望对你有一定的参考价值。
1、wait & notify 方法:
public class WaitAndNotify { private final int MAX_SIZE = 100; private LinkedList<Object> list = new LinkedList<Object>(); public void produce(int num) { synchronized (list) { while (list.size() + num > MAX_SIZE) { System.out.println("要生产的产品数:" + num + ", 现库存量为:" + list.size() + " 不能继续生产!"); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 1; i <= num; ++i) { list.add(new Object()); System.out.println("已生产产品数:" + num + ", 现产品量为:" + list.size()); } list.notifyAll(); } } public void consume(int num) { synchronized (list) { while (list.size() < num) { System.out.println("要消费的产品量:" + num + ", 现库存量为:" + list.size() + ",存量不足,暂时不能消费!"); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 1; i <= num; ++i) { list.remove(); System.out.println("已消费产品数" + num + ", 现存量为:" + list.size()); } list.notifyAll(); } } } public class Producer implements Runnable{ private int num; private WaitAndNotify storage; public Producer(WaitAndNotify storage) { this.storage = storage; } public void run() { produce(num); } public void produce(int num) { storage.produce(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public WaitAndNotify getStorage() { return storage; } public void setStorage(WaitAndNotify storage) { this.storage = storage; } } public class Consumer implements Runnable{ private int num; private WaitAndNotify storage; public Consumer(WaitAndNotify storage) { this.storage = storage; } public void run() { consume(num); } public void consume(int num) { storage.consume(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public WaitAndNotify getStorage() { return storage; } public void setStorage(WaitAndNotify storage) { this.storage = storage; } } public class WaitAndNotifyTest { public static void main(String[] args) { WaitAndNotify storage = new WaitAndNotify(); Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); p1.setNum(10); p2.setNum(20); p3.setNum(30); Consumer c1 = new Consumer(storage); Consumer c2 = new Consumer(storage); c1.setNum(15); c2.setNum(20); p1.run(); p2.run(); c1.run(); c2.run(); p3.run(); } }
运行结果如下:
已生产产品数:10, 现产品量为:1 已生产产品数:10, 现产品量为:2 已生产产品数:10, 现产品量为:3 已生产产品数:10, 现产品量为:4 已生产产品数:10, 现产品量为:5 已生产产品数:10, 现产品量为:6 已生产产品数:10, 现产品量为:7 已生产产品数:10, 现产品量为:8 已生产产品数:10, 现产品量为:9 已生产产品数:10, 现产品量为:10 已生产产品数:20, 现产品量为:11 已生产产品数:20, 现产品量为:12 已生产产品数:20, 现产品量为:13 已生产产品数:20, 现产品量为:14 已生产产品数:20, 现产品量为:15 已生产产品数:20, 现产品量为:16 已生产产品数:20, 现产品量为:17 已生产产品数:20, 现产品量为:18 已生产产品数:20, 现产品量为:19 已生产产品数:20, 现产品量为:20 已生产产品数:20, 现产品量为:21 已生产产品数:20, 现产品量为:22 已生产产品数:20, 现产品量为:23 已生产产品数:20, 现产品量为:24 已生产产品数:20, 现产品量为:25 已生产产品数:20, 现产品量为:26 已生产产品数:20, 现产品量为:27 已生产产品数:20, 现产品量为:28 已生产产品数:20, 现产品量为:29 已生产产品数:20, 现产品量为:30 已消费产品数15, 现存量为:29 已消费产品数15, 现存量为:28 已消费产品数15, 现存量为:27 已消费产品数15, 现存量为:26 已消费产品数15, 现存量为:25 已消费产品数15, 现存量为:24 已消费产品数15, 现存量为:23 已消费产品数15, 现存量为:22 已消费产品数15, 现存量为:21 已消费产品数15, 现存量为:20 已消费产品数15, 现存量为:19 已消费产品数15, 现存量为:18 已消费产品数15, 现存量为:17 已消费产品数15, 现存量为:16 已消费产品数15, 现存量为:15 要消费的产品量:20, 现库存量为:15,存量不足,暂时不能消费!
这里有个问题:为了唤醒正在等待的线程,应该使用notify还是notifyAll?
一般情况下,应该使用notifyAll,这是合理而保守的建议,它总会产生正确的结果,因为它可以保证将会唤醒所有需要被唤醒的线程。可能会唤醒一些其他的线程,但这不会影响程序的正确性,这些线程醒来之后,会检查他们正在等待的条件,如果发现条件并不满足,就会继续等待。
从优化的角度来讲,如果处于等待状态的所有线程都在等待同一个条件,而每次只有一个线程可以从这个条件被唤醒,那么就应该选择notify,而不是notifyAll。
2、BlockingQueue方法:
直接使用wait和notify就像用“并发编程语言”进行编程一样,而java.util.concurrent则提供了更高级的语言,没有理由在新代码中使用wait和notify.即使有,也是极少的。下面我们对比一下阻塞队列方法BlockingQueue,它是java.util.concurrent下的主要用来控制线程同步的工具。
public class BlockingQueue { private final int MAX_SIZE = 100; private LinkedBlockingQueue<Object> productList = new LinkedBlockingQueue<Object>(100); public void Produce(int num) { if (productList.size() == MAX_SIZE) { System.out.println("生产库存量为:" + MAX_SIZE + ",库存已满,暂时无法生产!"); } for (int i = 1; i <= num; ++i) { try { productList.put(new Object()); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("生产库存量为:" + productList.size()); } } public void Consume(int num) { if (productList.size() == 0) { System.out.println("消费库存量为0,暂时不能消费!"); } for (int i = 1; i <= num; ++i) { if (productList.size() < num) { System.out.println( "要消费的产品量:" + num + ", 现库存量为:" + productList.size() + ",存量不足,不能消费!"); } try { productList.take(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费库存量:" + productList.size()); } } public class Producer implements Runnable { private int num; private BlockingQueue storage; public Producer(BlockingQueue storage) { this.storage = storage; } public void run() { produce(num); } public void produce(int num) { storage.Produce(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public BlockingQueue getStorage() { return storage; } public void setStorage(BlockingQueue storage) { this.storage = storage; } } public class Consumer implements Runnable{ private int num; private BlockingQueue storage; public Consumer(BlockingQueue storage) { this.storage = storage; } public void run() { consume(num); } public void consume(int num) { storage.Consume(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public BlockingQueue getStorage() { return storage; } public void setStorage(BlockingQueue storage) { this.storage = storage; } } public class BlockingQueueTest { public static void main(String[] args) { BlockingQueue storage = new BlockingQueue(); Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); p1.setNum(10); p2.setNum(20); p3.setNum(30); Consumer c1 = new Consumer(storage); Consumer c2 = new Consumer(storage); c1.setNum(15); c2.setNum(20); p1.run(); p2.run(); c1.run(); c2.run(); p3.run(); } }
运行结果如下:
生产库存量为:1 生产库存量为:2 生产库存量为:3 生产库存量为:4 生产库存量为:5 生产库存量为:6 生产库存量为:7 生产库存量为:8 生产库存量为:9 生产库存量为:10 生产库存量为:11 生产库存量为:12 生产库存量为:13 生产库存量为:14 生产库存量为:15 生产库存量为:16 生产库存量为:17 生产库存量为:18 生产库存量为:19 生产库存量为:20 生产库存量为:21 生产库存量为:22 生产库存量为:23 生产库存量为:24 生产库存量为:25 生产库存量为:26 生产库存量为:27 生产库存量为:28 生产库存量为:29 生产库存量为:30 消费库存量:15 要消费的产品量:20, 现库存量为:15,存量不足,不能消费! 要消费的产品量:20, 现库存量为:14,存量不足,不能消费! 要消费的产品量:20, 现库存量为:13,存量不足,不能消费! 要消费的产品量:20, 现库存量为:12,存量不足,不能消费! 要消费的产品量:20, 现库存量为:11,存量不足,不能消费! 要消费的产品量:20, 现库存量为:10,存量不足,不能消费! 要消费的产品量:20, 现库存量为:9,存量不足,不能消费! 要消费的产品量:20, 现库存量为:8,存量不足,不能消费! 要消费的产品量:20, 现库存量为:7,存量不足,不能消费! 要消费的产品量:20, 现库存量为:6,存量不足,不能消费! 要消费的产品量:20, 现库存量为:5,存量不足,不能消费! 要消费的产品量:20, 现库存量为:4,存量不足,不能消费! 要消费的产品量:20, 现库存量为:3,存量不足,不能消费! 要消费的产品量:20, 现库存量为:2,存量不足,不能消费! 要消费的产品量:20, 现库存量为:1,存量不足,不能消费! 要消费的产品量:20, 现库存量为:0,存量不足,不能消费!
以上是关于关于生产者与消费者模式的两种实现方式的主要内容,如果未能解决你的问题,请参考以下文章
开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型
多线程之线程间协作的两种方式:waitnotifynotifyAll和Condition