zoukankan      html  css  js  c++  java
  • (转)生产者/消费者问题的多种Java实现方式

    参考来源:http://blog.csdn.net/monkey_d_meng/article/details/6251879/

    生产者/消费者问题的多种Java实现方式

    实质上,很多后台服务程序并发控制的基本原理都可以归纳为生产者/消费者模式,而这是恰恰是在本科操作系统课堂上老师反复讲解,而我们却视而不见不以为然的。在博文《一种面向作业流(工作流)的轻量级可复用的异步流水开发框架的设计与实现》中将介绍一种生产者/消费者模式的具体应用。

    生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强。因此本文只介绍同步机制实现的生产者/消费者问题。

    同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。

    (1)wait() / notify()方法

    (2)await() / signal()方法

    (3)BlockingQueue阻塞队列方法

    (4)PipedInputStream / PipedOutputStream

    本文只介绍最常用的前三种,第四种暂不做讨论,有兴趣的读者可以自己去网上找答案。

    一、wait() / notify()方法

    wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

    wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。

    notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

    光看文字可能不太好理解,咱来段代码就明白了:

    import java.util.LinkedList;  
      
    /** 
     * 仓库类Storage实现缓冲区              注意几个问题:策略模式    桥接模式
     *  
     */  
    public class Storage  
    {  
        // 仓库最大存储量  
        private final int MAX_SIZE = 100;  
      
        // 仓库存储的载体  
        private LinkedList<Object> list = new LinkedList<Object>();  
      
        // 生产num个产品  
        public void produce(int num)  
        {  
            // 同步代码段  
            synchronized (list)  
            {  
                // 如果仓库剩余容量不足  
                while (list.size() + num > MAX_SIZE)  
                {  
                    System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:"  
                            + list.size() + "/t暂时不能执行生产任务!");  
                    try  
                    {  
                        // 由于条件不满足,生产阻塞  
                        list.wait();  
                    }  
                    catch (InterruptedException e)  
                    {  
                        e.printStackTrace();  
                    }  
                }  
      
                // 生产条件满足情况下,生产num个产品  
                for (int i = 1; i <= num; ++i)  
                {  
                    list.add(new Object());  
                }  
      
                System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size());  
      
                list.notifyAll();  
            }  
        }  
      
        // 消费num个产品  
        public void consume(int num)  
        {  
            // 同步代码段  
            synchronized (list)  
            {  
                // 如果仓库存储量不足  
                while (list.size() < num)  
                {  
                    System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:"  
                            + list.size() + "/t暂时不能执行生产任务!");  
                    try  
                    {  
                        // 由于条件不满足,消费阻塞  
                        list.wait();  
                    }  
                    catch (InterruptedException e)  
                    {  
                        e.printStackTrace();  
                    }  
                }  
      
                // 消费条件满足情况下,消费num个产品  
                for (int i = 1; i <= num; ++i)  
                {  
                    list.remove();  
                }  
      
                System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size());  
      
                list.notifyAll();  
            }  
        }  
      
        // get/set方法  
        public LinkedList<Object> getList()  
        {  
            return list;  
        }  
      
        public void setList(LinkedList<Object> list)  
        {  
            this.list = list;  
        }  
      
        public int getMAX_SIZE()  
        {  
            return MAX_SIZE;  
        }  
    }  
    /** 
     * 生产者类Producer继承线程类Thread 
     *  
     * Email:530025983@qq.com 
     *  
     * @author MONKEY.D.MENG 2011-03-15 
     *  
     */  
    public class Producer extends Thread  
    {  
        // 每次生产的产品数量  
        private int num;  
      
        // 所在放置的仓库  
        private Storage storage;  
      
        // 构造函数,设置仓库  
        public Producer(Storage storage)  
        {  
            this.storage = storage;  
        }  
      
        // 线程run函数  
        public void run()  
        {  
            produce(num);  
        }  
      
        // 调用仓库Storage的生产函数  
        public void produce(int num)  
        {  
            storage.produce(num);  
        }  
      
        // get/set方法  
        public int getNum()  
        {  
            return num;  
        }  
      
        public void setNum(int num)  
        {  
            this.num = num;  
        }  
      
        public Storage getStorage()  
        {  
            return storage;  
        }  
      
        public void setStorage(Storage storage)  
        {  
            this.storage = storage;  
        }  
    }  
    /** 
     * 消费者类Consumer继承线程类Thread 
     *  
     * Email:530025983@qq.com 
     *  
     * @author MONKEY.D.MENG 2011-03-15 
     *  
     */  
    public class Consumer extends Thread  
    {  
        // 每次消费的产品数量  
        private int num;  
      
        // 所在放置的仓库  
        private Storage storage;  
      
        // 构造函数,设置仓库  
        public Consumer(Storage storage)  
        {  
            this.storage = storage;  
        }  
      
        // 线程run函数  
        public void run()  
        {  
            consume(num);  
        }  
      
        // 调用仓库Storage的生产函数  
        public void consume(int num)  
        {  
            storage.consume(num);  
        }  
      
        // get/set方法  
        public int getNum()  
        {  
            return num;  
        }  
      
        public void setNum(int num)  
        {  
            this.num = num;  
        }  
      
        public Storage getStorage()  
        {  
            return storage;  
        }  
      
        public void setStorage(Storage storage)  
        {  
            this.storage = storage;  
        }  
    }  
    /** 
     * <a href="http://lib.csdn.net/base/softwaretest" class='replace_word' title="软件测试知识库" target='_blank' style='color:#df3434; font-weight:bold;'>测试</a>类Test 
     *  
     * Email:530025983@qq.com 
     *  
     * @author MONKEY.D.MENG 2011-03-15 
     *  
     */  
    public class Test  
    {  
        public static void main(String[] args)  
        {  
            // 仓库对象  
            Storage storage = new Storage();  
      
            // 生产者对象  
            Producer p1 = new Producer(storage);  
            Producer p2 = new Producer(storage);  
            Producer p3 = new Producer(storage);  
            Producer p4 = new Producer(storage);  
            Producer p5 = new Producer(storage);  
            Producer p6 = new Producer(storage);  
            Producer p7 = new Producer(storage);  
      
            // 消费者对象  
            Consumer c1 = new Consumer(storage);  
            Consumer c2 = new Consumer(storage);  
            Consumer c3 = new Consumer(storage);  
      
            // 设置生产者产品生产数量  
            p1.setNum(10);  
            p2.setNum(10);  
            p3.setNum(10);  
            p4.setNum(10);  
            p5.setNum(10);  
            p6.setNum(10);  
            p7.setNum(80);  
      
            // 设置消费者产品消费数量  
            c1.setNum(50);  
            c2.setNum(20);  
            c3.setNum(30);  
      
            // 线程开始执行  
            c1.start();  
            c2.start();  
            c3.start();  
            p1.start();  
            p2.start();  
            p3.start();  
            p4.start();  
            p5.start();  
            p6.start();  
            p7.start();  
        }  
    }  
    【要消费的产品数量】:50   【库存量】:0 暂时不能执行生产任务!  
    【要消费的产品数量】:30   【库存量】:0 暂时不能执行生产任务!  
    【要消费的产品数量】:20   【库存量】:0 暂时不能执行生产任务!  
    【已经生产产品数】:10    【现仓储量为】:10  
    【要消费的产品数量】:20   【库存量】:10    暂时不能执行生产任务!  
    【要消费的产品数量】:30   【库存量】:10    暂时不能执行生产任务!  
    【要消费的产品数量】:50   【库存量】:10    暂时不能执行生产任务!  
    【已经生产产品数】:10    【现仓储量为】:20  
    【要消费的产品数量】:50   【库存量】:20    暂时不能执行生产任务!  
    【要消费的产品数量】:30   【库存量】:20    暂时不能执行生产任务!  
    【已经消费产品数】:20    【现仓储量为】:0  
    【已经生产产品数】:10    【现仓储量为】:10  
    【已经生产产品数】:10    【现仓储量为】:20  
    【已经生产产品数】:80    【现仓储量为】:100  
    【要生产的产品数量】:10   【库存量】:100   暂时不能执行生产任务!  
    【已经消费产品数】:30    【现仓储量为】:70  
    【已经消费产品数】:50    【现仓储量为】:20  
    【已经生产产品数】:10    【现仓储量为】:30  
    【已经生产产品数】:10    【现仓储量为】:40  
    

      

  • 相关阅读:
    15. DML, DDL, LOGON 触发器
    5. 跟踪标记 (Trace Flag) 834, 845 对内存页行为的影响
    4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志
    14. 类似正则表达式的字符处理问题
    01. SELECT显示和PRINT打印超长的字符
    3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息
    2. 跟踪标记 (Trace Flag) 3604, 3605 输出DBCC命令结果
    1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
    0. 跟踪标记 (Trace Flag) 简介
    SpringBoot + Redis + Shiro 实现权限管理(转)
  • 原文地址:https://www.cnblogs.com/1020182600HENG/p/7344465.html
Copyright © 2011-2022 走看看