生产者/消费者模式 (java)
2016-03-31 20:38
591 查看
生产者/消费者模式要求在同一个进程地址空间内执行的两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
优点:
(1)解耦。假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
(2)支持并发。生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会浪费时间。
(3)支持忙闲不均。缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
优点:
(1)解耦。假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
(2)支持并发。生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会浪费时间。
(3)支持忙闲不均。缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
public class ProducerConsumer { public static void main(String[] args) { // TODO 自动生成方法存根 Box box = new Box(); Producer p = new Producer(box); Consumer c = new Consumer(box); p.start(); c.start(); } }
public class Consumer extends Thread { private Box box; private String name; public Consumer(Box b) { box = b; } public void run() { int value = 0; while (true) { int realNum = Box.getRealNum(); if (realNum > 0) { value = box.get(); System.out.println("取出的元素是:" + value); } try { sleep((int) (Math.random() * 5000)); } catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); } }// while }// run }
public class Producer extends Thread { private Box box; private String name; private static int maxCap = 5;// 最大的缓冲区大小 public Producer(Box b) { box = b; } public void run() { while (true) { int realNum = Box.getRealNum(); if (realNum < maxCap) { int random = (int) (Math.random() * 10); box.put(random); System.out.println("插入的元素是: " + random); } try { sleep((int) (Math.random() * 5000)); } catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); } }// while }// run }
public class Box { private static int maxCap = 5;// 最大的缓冲区大小 private static int realNum = 0;// 缓冲区中实际元素的数目 private int[] arr = new int[5];// 声明一个数组作为缓冲区 private int getValue;// get()返回的数字值 /** * 返回缓冲区中现有元素个数 * * @return */ public static synchronized int getRealNum() { return realNum; } /** * 获取缓冲区的一个元素 * * @return */ public synchronized int get() { if (realNum < maxCap) {// 缓冲区未满,唤醒生产者插入元素 notifyAll(); } while (realNum == 0) {// 缓冲区中没有元素 try { // 等待生产者写入数据 wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }// while if (realNum > 0) {// 缓冲区不为空 System.out.println("取出前缓冲区有" + realNum + "个元素"); getValue = arr[--realNum]; System.out.println("取出后缓冲区有" + realNum + "个元素"); } // 遍历输出缓存区所有元素 System.out.print("取出后缓冲区剩下元素: "); for (int i = 0; i < realNum; i++) { System.out.print(arr[i] + "、"); } System.out.println(); return getValue; }// get /** * 向缓冲区插入一个元素 * * @param value */ public synchronized void put(int value) { if (realNum < maxCap) {// 缓冲区未满,唤醒生产者插入元素 notifyAll(); } while (realNum == maxCap) { try { // 缓冲区满,等待消费者取走元素 wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (realNum < maxCap) { System.out.println("插入前缓冲区有" + realNum + "个元素"); arr[realNum++] = value; System.out.println("插入后缓冲区有" + realNum + "个元素"); } // 遍历输出缓存区所有元素 System.out.print("插入后缓冲区有元素: "); for (int i = 0; i < realNum; i++) { System.out.print(arr[i] + "、"); } System.out.println(); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树