Design Pattern: Producer Consumer 模式
 

2009-09-21 来源:riabook.cn

 

Producer Consumer模式与 Guarded Suspension 模式 是类似的,只不过Guarded Suspension模式并不限制缓冲区的长度,Producer Consumer模式假设所生产的产品放置在一个长度有限制的缓冲区(就像是一个产品桌,它可以摆放的空间是有限的),如果缓冲区满了,则生产者必须停止继续将产品放到缓冲区中,直到消费者取走了产品而有了空间,而如果缓冲区中没有产品,当然消费者必须等待,直到有新的产品放到缓冲区中。

一个简单的 UML 顺序图如下所示:

ProducerConsumer

简单来说,Producer Consumer模式就像是加上了双重防护与等待的Guarded Suspension模式,而它的两个防护与等待的条件洽好相反,一个用Java实现的简单流程架构如下:

  • ProductTable.java
    import java.util.LinkedList;
    
    public class ProductTable {
        private LinkedList products = new LinkedList();
    
        public synchronized void addProduct(Product product) {
            while(products.size() >= 2) { // 容量限制为 2
                try {
                    wait();
                }
                catch(InterruptedException e) {}
            }
    
            products.addLast(product);
            notifyAll();
        }
       
        public synchronized Product getProduct() {
            while(products.size() <= 0) {
                try {
                    wait();
                }
                catch(InterruptedException e) {}
            }
    
            Product product = (Product) products.removeFirst();
            notifyAll();
         
            return product;
        }
    } 

以下举一个最简单的:生产者每次生产一个整数并放置在桌子上,而消费者消耗整数,桌子上一次只能放置一个整数,如果桌子上已有整数,则生产者等待消费者将整数消耗并通知生产者生产下一个整数,如果桌子上没有整数,则消费者等待生产者生产整数并通知消费者可以消耗整数。

  • Producer.java
    public class Producer extends Thread {
        private ProductTable productTable;
       
        public Producer(ProductTable productTable) {
            this.productTable = productTable;
        }
       
        public void run() {
            System.out.println("Produce integer......");
            for(int product = 1; product <= 10; product++) {
                try {
                    // wait for a random time
                    Thread.sleep((int) Math.random() * 3000);
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }
                productTable.setIntProduct(product);
            }      
        }
    } 
    
  • Consumer.java
    public class Consumer extends Thread {
        private ProductTable productTable;
       
        public Consumer(ProductTable productTable) {
            this.productTable = productTable;
        }
       
        public void run() {
            for(int i = 1; i <= 10; i++) {
                try {
                    // wait for a random time
                    Thread.sleep((int) (Math.random() * 3000));
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }
                productTable.getProductInt();
            }
        }
    } 
    

生产者将产品放至桌上,而消费者将产品从桌上取走,所以桌子是个维护是否让被放置或消耗产品的地方,由它来决定谁必须等待与通知:

  • ProductTable.java
    public class ProductTable {
        private int productInt = -1; // -1 for no product
    
        public synchronized void setIntProduct(int product) {
            if(productInt != -1) {
                try {
                    wait();
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            productInt = product;
            System.out.println("set (" + product + ")");
            notify();
        }
       
        public synchronized int getProductInt() {
            if(productInt == -1) {
                try {
                    wait();
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            int p = productInt;
            System.out.println("Get (" + productInt + ")");
            productInt = -1;
                  
            notify();
          
            return p;
        }
    } 
    

生产者会生产10个整数,而消费者会消耗10个整数,由于桌上只能放置一个整数,所以每生产一个就消耗一个。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织