美文网首页
你一定不知道如何用Java高效解决生产者和消费者的经典问题

你一定不知道如何用Java高效解决生产者和消费者的经典问题

作者: WHOKNOWME | 来源:发表于2016-09-28 17:50 被阅读1117次
    你一定不知道如何用Java高效解决生产者和消费者的经典问题

    很久之前面试遇到过这个问题,当时懵逼了,结果啪啪啪就跪了。不过最近有在看java方面的知识,所以,从新来回顾这个让我伤心的经典问题。

    问题是这样的:

    要求设计这两个进程使其满足如下要求.
    1.生产顺序按照队列的方式,先进先出.
    2.生产和消费可以同时进行
    3.当生产容量满了后,不能继续生产,消费完了后不能继续消费
    4.当生产容量满了或者消费完了,要节约CPU开销(不能使用sleep( ) )
    5.尽量少定义变量,高效率实现.

    看到题目,我又懵逼了。不过,先冷静下来,仔细的研读一下题目,你会发现出题者想考的是线程并发和线程池的问题。我觉得第一时刻把握住出题者的意图是非常重要的(滚! 你是在传授考试技巧么).

    要求1 是限制我们去采用一个Queue,特点是先进先出。
    要求2,3 是需要考虑线程的同步问题。
    要求4,5 需要考虑性能的问题。

    ok,到目前为止,我想到的是通过锁机制来实现消费者和生产者,即在生产者中判断当前的产量是否达到最大,如果达到最大产能,那么生产者需要休息一下了,因为此刻仓库已经满了。同时需要通知到消费者来进行消费。那么对于消费者,也存在类似的问题,就是消费者在发现仓库有商品空位的时候需要去通知生产者来生产商品,通过这样协作方式,使生产者和消费者产生一种高效的配合机制。这才是老板所希望看到的。

    直到今天,我发现其实是可以采用LinkedBlockingQueue来实现解决上面的问题。关于LinkedBlockingQueue的说明请移步至:http://www.jianshu.com/p/cc2281b1a6bc

    下面是我的一种实现方式,仅供参考,有问题欢迎拍砖。

    上来我就创建一个消费者,让他负责消费那些生产出来的商品。

    package com.iknow;
    public class Consumer extends Thread {
        private Storage storage;
        public Consumer(Storage storage) {
            this.storage = storage;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    Storage.Goods goods = storage.goods.take();
                    System.out.printf(String.valueOf(storage.goods.size())+"\\n");
                    Thread.sleep(300);
                    System.out.println("消费" + " " + goods.getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    上来我又就创建一个生产者,其实也是一个线程类。

    package com.iknow;
    public class Producer extends Thread {
    
        private Storage storage;
        private int i = 0;
        public Producer(Storage storage) {
            this.storage = storage;
        }
    
        @Override
        public void run() {
    
            while (true) {
                try {
                    storage.goods.put(new Storage.Goods("苹果"+ i));
                    Thread.sleep(100);
                    i++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    

    有了生产者和消费者线程还不够,我这里还给了一个仓库,仓库中包含一个商品类。

    package com.iknow;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    public class Storage {
    
        public static int MAX_COUNT = 5;    //容量为5
    
        public BlockingQueue<Goods> goods = new LinkedBlockingQueue<Goods>(MAX_COUNT);
        public Storage() {
        }
        public static class Goods {
            int id;
            String name;
    
            public Goods(String name) {
                this.name = name;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    }
    

    接下来布置一个场景:

    package com.iknow;
    import java.util.concurrent.*;
    
    public class TestThread {
        public static Object obj = new Object();
    
        public static void main(String[] args) throws InterruptedException {
    
            ExecutorService service = Executors.newCachedThreadPool();
            Storage storage = new Storage();
            Consumer consumer1 = new Consumer(storage);
            Consumer consumer2 = new Consumer(storage);
            Producer producer = new Producer(storage);
    
            service.submit(consumer1);
            service.submit(consumer2);
            service.submit(producer);
    
        }
    }
    

    THE END
    国际惯例,附上微信二维码


    我的微信我的微信

    相关文章

      网友评论

          本文标题:你一定不知道如何用Java高效解决生产者和消费者的经典问题

          本文链接:https://www.haomeiwen.com/subject/waghyttx.html