美文网首页
牛奶发酵剂奶酪,设计生产系统

牛奶发酵剂奶酪,设计生产系统

作者: 站在海边看远方 | 来源:发表于2020-11-03 15:23 被阅读0次

    题目描述如下:

    有一家生产奶酪的厂家,每天需要生产100000份奶酪卖给超市,通过一辆送货车发货,送货车辆每次送100份。
    厂家有一个容量为1000份的冷库,用于奶酪保鲜,生产的奶酪需要先存放在冷库,运输车辆从冷库取货。
    厂家有三条生产线,分别是牛奶供应生产线,发酵剂制作生产线,奶酪生产线。生产每份奶酪需要2份牛奶和1份发酵剂。
    请设计生产系统。

    根据以下要求,我们可以考虑这么几个方面

    • 牛奶生产和发酵剂生产作为生产者,奶酪生产作为消费者
    • 奶酪生产作为生产者,货车发车作为消费者
    • 牛奶存储和发酵剂存储以及奶酪存储,使用3个阻塞队列暂存
    • 货车装车从奶酪队列里每取一百次发一次车
    • 一共4个生产者,2个消费者,3个阻塞队列

    下面是代码实现

    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * 生产奶酪
     *
     * @author since
     * @date 2020-11-02 16:04
     **/
    public class Cheese {
    
        /**
         * 每天生产奶酪的总量
         */
        private static final Integer TOTAL_PRODUCTION = 100000;
    
        /**
         * 牛奶的数量-200000/天
         */
        private static final AtomicInteger MILK_SIZE = new AtomicInteger(0);
    
        /**
         * 发酵剂的数量-100000/天
         */
        private static final AtomicInteger STARTER_SIZE = new AtomicInteger(0);
    
        /**
         * 奶酪的数量-100000/天
         */
        private static final AtomicInteger CHEESE_SIZE = new AtomicInteger(0);
    
        /**
         * 取奶酪的次数
         */
        private static final AtomicInteger CHEESE_TAKE_TIMES = new AtomicInteger(0);
    
    
        /**
         * 阻塞队列,用于存放奶酪,生产者是牛奶和发酵剂,消费者是货车发货,每次发100份
         */
        private static final BlockingQueue<Integer> CHEESE_QUEUE = new LinkedBlockingQueue<>(1000);
    
        /**
         * 阻塞队列,用于存放生产的牛奶,生产者是牛奶,消费者是奶酪生产
         */
        private static final BlockingQueue<Integer> MILK_QUEUE = new LinkedBlockingQueue<>(2);
    
        /**
         * 阻塞队列,用于存放生产的发酵剂,生产者是发酵剂,消费者是奶酪生产
         */
        private static final BlockingQueue<Integer> STARTER_QUEUE = new LinkedBlockingQueue<>(1);
    
        /**
         * 奶酪生产线程池
         */
        private static final ThreadPoolExecutor CHEESE_PRODUCER = new ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1), new ThreadFactoryBuilder().setNameFormat("cheese-producer-%d").build(), (r, executor) -> System.out.println("Cheese Reject Task"));
    
        /**
         * 发酵剂生产线程池
         */
        private static final ThreadPoolExecutor STARTER_PRODUCER = new ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1), new ThreadFactoryBuilder().setNameFormat("starter-producer-%d").build(), (r, executor) -> System.out.println("Starter Reject Task"));
    
        /**
         * 牛奶生产线程池
         */
        private static final ThreadPoolExecutor MILK_PRODUCER = new ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1), new ThreadFactoryBuilder().setNameFormat("milk-producer-%d").build(), (r, executor) -> System.out.println("Milk Reject Task"));
    
        /**
         * 货车发货线程池
         */
        private static final ThreadPoolExecutor TRUCKING = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1), new ThreadFactoryBuilder().setNameFormat("trucking-%d").build(), (r, executor) -> System.out.println("Trunking Reject Task"));
    
    
        /**
         * 奶酪生产线程
         */
        static class CheeseProducer implements Runnable {
    
            @Override
            public void run() {
                while (CHEESE_SIZE.get() < TOTAL_PRODUCTION) {
                    try {
                        //发酵剂取1
                        STARTER_QUEUE.take();
                        //System.out.println("生产奶酪,发酵剂取1");
    
                        //牛奶取2
                        MILK_QUEUE.take();
                        MILK_QUEUE.take();
    
                        //System.out.println("生产奶酪,发酵剂取2");
    
                        //奶酪生产1
                        CHEESE_QUEUE.put(1);
                        //System.out.println("生产1份奶酪");
    
                        //生产数量加1
                        int i = CHEESE_SIZE.incrementAndGet();
    
                        if (CHEESE_SIZE.get() == TOTAL_PRODUCTION) {
                            System.out.println("本日奶酪已生产完,共" + i + "份");
                        }
    
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    
        /**
         * 发酵剂生产线程
         */
        static class StarterProducer implements Runnable {
    
            @Override
            public void run() {
                while (STARTER_SIZE.get() < TOTAL_PRODUCTION) {
                    try {
                        STARTER_QUEUE.put(1);
                        //System.out.println("生产1份发酵剂");
                        //发酵剂+1
                        int i = STARTER_SIZE.incrementAndGet();
                        if (STARTER_SIZE.get() == TOTAL_PRODUCTION) {
                            System.out.println("本日发酵剂已生产完,共" + i + "份");
                        }
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
    
            }
        }
    
        /**
         * 牛奶生产线程
         */
        static class MilkProducer implements Runnable {
    
            @Override
            public void run() {
                while (MILK_SIZE.get() < TOTAL_PRODUCTION * 2) {
                    try {
                        MILK_QUEUE.put(1);
                        //System.out.println("生产1份牛奶");
    
                        //牛奶数量+1
                        int i = MILK_SIZE.incrementAndGet();
                        if (MILK_SIZE.get() == TOTAL_PRODUCTION * 2) {
                            System.out.println("本日牛奶已生产完,共" + i + "份");
                        }
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    
        /**
         * 货车发货线程
         */
        static class Trucking implements Runnable {
            @Override
            public void run() {
    
                while (true) {
                    try {
                        //取奶酪装车准备发货
                        CHEESE_QUEUE.take();
    
                        int i1 = CHEESE_TAKE_TIMES.incrementAndGet();
    
                        if (i1 % 100 == 0) {
                            System.out.println("货车装满100份,发车");
                        }
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
    
            }
        }
    
        public static void main(String[] args) {
            CHEESE_PRODUCER.execute(new CheeseProducer());
    
            STARTER_PRODUCER.execute(new StarterProducer());
    
            MILK_PRODUCER.execute(new MilkProducer());
    
            TRUCKING.execute(new Trucking());
    
            while (true) {
                if (CHEESE_SIZE.get() == TOTAL_PRODUCTION) {
                    MILK_PRODUCER.shutdown();
                    STARTER_PRODUCER.shutdown();
                    CHEESE_PRODUCER.shutdown();
                    TRUCKING.shutdown();
                    System.exit(0);
                }
    
            }
        }
    
    }
    
    

    如上代码就是一个典型的生产者消费者代码,而且都是单线程生产和消费。

    • 1份奶酪需要2份牛奶和1份发酵剂,确定了2个生产者和一个消费者。
    • 货车从冷库里取奶酪,奶酪需要放在冷库里,确定了一个生产者和一个消费者
    • 题目要求的所有的生产和消费行为都是单线程的

    我自己在实现的时候,从冷库取奶酪的时候,使用了5个线程从冷库里取奶酪,这样会导致在计算取多少次的时候,会导致数据打印出来会乱序。

    题目要求的是每100份奶酪发一次车,所以需要在冷库里取100次,下面如果不加锁,会有问题,导致乱序

    所以货车如果改成多线程,下面这几行代码需要加锁保证顺序

      CHEESE_QUEUE.take();
    
      int i1 = CHEESE_TAKE_TIMES.incrementAndGet();
    
      if (i1 % 100 == 0) {
            System.out.println("货车装满100份,发车");
      }
    

    相关文章

      网友评论

          本文标题:牛奶发酵剂奶酪,设计生产系统

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