Chinaunix首页 | 论坛 | 博客
  • 博客访问: 830330
  • 博文数量: 247
  • 博客积分: 166
  • 博客等级: 入伍新兵
  • 技术积分: 2199
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-15 16:10
文章分类

全部博文(247)

文章存档

2017年(1)

2015年(63)

2014年(80)

2013年(94)

2012年(9)

分类: Java

2014-02-17 22:38:22

生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。
生产者消费者模式是为了解决哪一类问题而产生的呢?在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。

生产者消费者的关系如下图所示:

  


生产者消费者模式的原理描述:
(1)生产者仅仅在仓储未满时候生产,仓满则停止生产。
(2)消费者仅仅在仓储有产品时候才能消费,仓空则等待。
(3)当消费者发现仓储没产品可消费时候会通知生产者生产。
(4)生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
下面通过一个例子描述下生产者消费者模式的使用。 
1、第一个文件ProductStorage.java

点击(此处)折叠或打开

  1. /**
  2.  * 库存商品管理类
  3.  */
  4. public class ProductStorage {

  5.     /**
  6.      * 最大库存量
  7.      */
  8.     public static final int Maximum = 100;
  9.     
  10.     /**
  11.      * 当前库存量
  12.      */
  13.     public static int Currentimum = 50;
  14.     
  15.     /**
  16.      * 库存管理实例
  17.      */
  18.     private static ProductStorage instance;
  19.     
  20.     private ProductStorage(){}
  21.     
  22.     /**
  23.      * 获取单例
  24.      * @return
  25.      */
  26.     public static ProductStorage getInstance(){
  27.         if(instance == null){
  28.             instance = new ProductStorage();
  29.         }
  30.         return instance;
  31.     }
  32.     
  33.     /**
  34.      * 生产产品
  35.      */
  36.     public synchronized void product(){
  37.         while(Currentimum >= Maximum/2){
  38.             try {
  39.                 wait();
  40.             } catch (InterruptedException e) {
  41.                 e.printStackTrace();
  42.             }
  43.         }
  44.         Currentimum++;
  45.         System.out.println("当前线程:"+Thread.currentThread().getName() + "--生产者生产了一个商品,当前库存量:"+ Currentimum);
  46.         notifyAll();
  47.     }
  48.     
  49.     /**
  50.      * 消费产品
  51.      */
  52.     public synchronized void consume(){
  53.         while(Currentimum <= 0){
  54.             try {
  55.                 wait();
  56.             } catch (InterruptedException e) {
  57.                 e.printStackTrace();
  58.             }
  59.         }
  60.         Currentimum--;
  61.         System.out.println("当前线程:"+Thread.currentThread().getName() + "--消费者消费了一个商品,当前库存量:"+ Currentimum);
  62.         notifyAll();
  63.     }
  64. }

2、第二个文件Producter.java

点击(此处)折叠或打开

  1. /**
  2.  * 商品生产者模型
  3.  */
  4. public class Producter implements Runnable {
  5.     
  6.     @Override
  7.     public void run(){
  8.         while(true){
  9.             try {
  10.                 Thread.sleep(500);
  11.             } catch (InterruptedException e) {
  12.                 e.printStackTrace();
  13.             }
  14.             ProductStorage.getInstance().product();
  15.         }
  16.     }
  17. }
3、第三个文件Consumer.java
 

点击(此处)折叠或打开

  1. /**
  2.  * 商品消费者模型
  3.  */
  4. public class Consumer implements Runnable{

  5.     @Override
  6.     public void run() {
  7.         while(true){
  8.             try {
  9.                 Thread.sleep(1000);
  10.             } catch (InterruptedException e) {
  11.                 e.printStackTrace();
  12.             }
  13.             ProductStorage.getInstance().consume();
  14.         }
  15.         
  16.     }
  17. }
4、第四个文件TestMain.java
 

点击(此处)折叠或打开

  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;

  3. public class TestMain {

  4.     public static void main(String [] args){
  5.         startProductThread();
  6.         startConsumThread();
  7.     }
  8.     
  9.     /**
  10.      * 开启生产者线程
  11.      */
  12.     public static void startProductThread(){
  13.         System.out.println("--生产者线程执行开始--");
  14.         int pThreadSize = 10;
  15.         ExecutorService pool = Executors.newFixedThreadPool(pThreadSize);
  16.         for(int i=0;i<pThreadSize;i++){
  17.             Producter productThread = new Producter();
  18.             Thread thread = new Thread(productThread);
  19.             pool.execute(thread);
  20.         }
  21.         System.out.println("--生产者线程执行结束--");
  22.     }
  23.     
  24.     /**
  25.      * 开启消费者线程
  26.      */
  27.     public static void startConsumThread(){
  28.         System.out.println("--消费者线程执行开始--");
  29.         int pThreadSize = 10;
  30.         ExecutorService pool = Executors.newFixedThreadPool(pThreadSize);
  31.         for(int i=0;i<pThreadSize;i++){
  32.             Consumer consumeThread = new Consumer();
  33.             Thread thread = new Thread(consumeThread);
  34.             pool.execute(thread);
  35.         }
  36.         System.out.println("--消费者线程执行结束--");
  37.     }
  38. }

5、生产者消费者模式的优点:
(1)将生产模块和消费模块分隔开,从而降低了程序的耦合,便于程序的扩展和维护。
(2)将生产模块和消费模块的分隔,可使生产模块的运行不再依赖消费模块的执行,由同步改为异步执行并且都可支持并发,从而大大提高了程序的效率。
(3)生成者生产的数据存放在缓冲区中,消费者可以按照自己的逻辑来取出数据处理,从而可以有效避免消费模块任务执行负载不均的问题。
阅读(572) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~