设计模式—生产者消费者模式

介绍


1.生产者生产数据到缓冲区中,消费者从缓冲区中取数据。
2.如果缓冲区已经满了,则生产者线程阻塞。
3.如果缓冲区为空,那么消费者线程阻塞。

2种实现方式

实际上还有一种await、signalAll的实现方式,这里我排除了,因这里需要涉及到concurrent包下Lock的东西,精力有限,重点在于设计模式的理解,所以暂时TODO。
这里只实现sychronized和bloackQueue的例子。

wait / notify

我直接贴出三个角色的代码,然后测试的时候我刻意让消费速度小于生产速度。

BufferArea.java

产品池,封装了存和取俩个方法以便让生产者和消费者使用。
为什么它不是一个Thread的子类也能wait和notify,因为wait和notify是Object的方法。


    package com.zj.dp.生产者消费者模式.wait_notify;

    public class BufferArea {

        //当前资源数量的记数值
        private int currNum = 0;

        //资源池中允许存放的资源数目
        private int maxSize = 10;

        /**
         * 从资源池中取走资源
         */
        public synchronized void get() {

            if (currNum > 0) {
                currNum--;
                System.out.println("Cosumer__" + Thread.currentThread().getName() + "消耗一件资源," + "当前缓冲区有" + currNum + "个");

                //通知生产者生产资源
                notifyAll();
            } else {
                try {

                    //如果没有资源,则Cosumer__进入等待状态
                    System.out.println("Cosumer__" + Thread.currentThread().getName() + ":当前缓冲区资源不足,进入等待状态");
                    wait();


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }


        /**
         * 向缓冲区中添加资源
         */
        public synchronized void put() {
            //若当前缓冲区内的资源计数小于最大size数,才加
            if (currNum < maxSize) {
                currNum++;
                System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有"+ currNum + "个");

                //通知等待的消费者
                notifyAll();
            } else {
                //若当前缓冲区内的资源计数大于最大size数,则等待
                try {
                    System.out.println(Thread.currentThread().getName() + "线程进入等待  << 当前缓冲区内的资源计数大于最大size数");
                    wait();//生产者进入等待状态,并释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

Consumer.java

消费者,代码很简单。


    package com.zj.dp.生产者消费者模式.wait_notify;

    public class Consumer extends Thread {

        private BufferArea mBufferArea;

        public Consumer(BufferArea bufferArea) {
            this.mBufferArea = bufferArea;
            setName("Consumer_"+getName());
        }

        @Override
        public void run() {
            //不断的取出资源
            while (true) {
                sleepSomeTime();
                mBufferArea.get();
            }
        }

        private void sleepSomeTime() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

Producer.java

生产者,代码很简单。


    package com.zj.dp.生产者消费者模式.wait_notify;

    public class Producer extends Thread {

        private BufferArea mBufferArea;
        public Producer(BufferArea bufferArea){
            this.mBufferArea = bufferArea;
            setName("Producer_"+getName());
        }

        @Override
        public void run() {
            //不断地生产资源
            while(true){
                sleepSomeTime();
                mBufferArea.put();
            }
        }

        private void sleepSomeTime() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

日志输出


    输出结果:

    Producer_Thread-4生产一件资源,当前资源池有1个
    Producer_Thread-3生产一件资源,当前资源池有2个
    Producer_Thread-5生产一件资源,当前资源池有3个
    Producer_Thread-4生产一件资源,当前资源池有4个
    Producer_Thread-3生产一件资源,当前资源池有5个
    Producer_Thread-5生产一件资源,当前资源池有6个
    Producer_Thread-3生产一件资源,当前资源池有7个
    Producer_Thread-4生产一件资源,当前资源池有8个
    Producer_Thread-5生产一件资源,当前资源池有9个
    Producer_Thread-3生产一件资源,当前资源池有10个
    Producer_Thread-5线程进入等待  << 当前缓冲区内的资源计数大于最大size数
    Producer_Thread-4线程进入等待  << 当前缓冲区内的资源计数大于最大size数
    Producer_Thread-3线程进入等待  << 当前缓冲区内的资源计数大于最大size数

    --》讲解:先是3个生产者线程生产满了10个(maxSize)产品,然后就都进入了等待

    Cosumer__Consumer_Thread-0消耗一件资源,当前缓冲区有9个
    Cosumer__Consumer_Thread-2消耗一件资源,当前缓冲区有8个
    Cosumer__Consumer_Thread-1消耗一件资源,当前缓冲区有7个

    --》讲解:3个消费者消费了3个产品

    Producer_Thread-5生产一件资源,当前资源池有8个
    Producer_Thread-4生产一件资源,当前资源池有9个
    Producer_Thread-3生产一件资源,当前资源池有10个

    --》讲解:生产者立马又生产3个

    Producer_Thread-5线程进入等待  << 当前缓冲区内的资源计数大于最大size数
    Producer_Thread-4线程进入等待  << 当前缓冲区内的资源计数大于最大size数
    Producer_Thread-3线程进入等待  << 当前缓冲区内的资源计数大于最大size数

    --》讲解:又消费3个

    Cosumer__Consumer_Thread-0消耗一件资源,当前缓冲区有9个
    Cosumer__Consumer_Thread-1消耗一件资源,当前缓冲区有8个
    Cosumer__Consumer_Thread-2消耗一件资源,当前缓冲区有7个

    --》讲解:又生产3个 ...后续大致也就这样,子子孙孙无穷尽也...不贴了...

BlockQueue

BlockQueueBufferArea


    package com.zj.dp.生产者消费者模式.blockingqueue;

    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;

    public class BlockQueueBufferArea {

        BlockingQueue<Integer> mProductPoll = new LinkedBlockingQueue(10);

        public void put() {
            try {
                System.out.println(Thread.currentThread().getName() +   "产品池被放入了一个资源");
                mProductPoll.put(1);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void get() {
            try {
                System.out.println(Thread.currentThread().getName() +   "产品池被取走了一个资源");
                mProductPoll.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

Consumer


    package com.zj.dp.生产者消费者模式.blockingqueue;


    public class Consumer extends Thread {

        private BlockQueueBufferArea mBufferArea;

        public Consumer(BlockQueueBufferArea bufferArea) {
            this.mBufferArea = bufferArea;
            setName("Consumer_"+getName());
        }

        @Override
        public void run() {
            //不断的取出资源
            while (true) {
                sleepSomeTime();
                mBufferArea.get();
            }
        }

        private void sleepSomeTime() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

Producer


    package com.zj.dp.生产者消费者模式.blockingqueue;


    public class Consumer extends Thread {

        private BlockQueueBufferArea mBufferArea;

        public Consumer(BlockQueueBufferArea bufferArea) {
            this.mBufferArea = bufferArea;
            setName("Consumer_"+getName());
        }

        @Override
        public void run() {
            //不断的取出资源
            while (true) {
                sleepSomeTime();
                mBufferArea.get();
            }
        }

        private void sleepSomeTime() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

Test


    package com.zj.dp.生产者消费者模式.blockingqueue;


    public class Test {

        public static void main(String[] args) {

            BlockQueueBufferArea bufferArea = new BlockQueueBufferArea();

            Consumer consumer1 = new Consumer(bufferArea);
            Consumer consumer2 = new Consumer(bufferArea);
            Consumer consumer3 = new Consumer(bufferArea);

            Producer producer1 = new Producer(bufferArea);
            Producer producer2 = new Producer(bufferArea);
            Producer producer3 = new Producer(bufferArea);


            consumer1.start();
            consumer2.start();
            consumer3.start();

            producer1.start();
            producer2.start();
            producer3.start();
        }

    }

输出


    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Producer_Thread-4产品池被放入了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Producer_Thread-4产品池被放入了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-4产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Producer_Thread-4产品池被放入了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Consumer_Thread-1产品池被取走了一个资源
    Consumer_Thread-2产品池被取走了一个资源
    Consumer_Thread-0产品池被取走了一个资源
    Producer_Thread-4产品池被放入了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Consumer_Thread-0产品池被取走了一个资源
    Consumer_Thread-1产品池被取走了一个资源
    Consumer_Thread-2产品池被取走了一个资源
    Producer_Thread-3产品池被放入了一个资源
    Producer_Thread-5产品池被放入了一个资源
    Producer_Thread-4产品池被放入了一个资源

Thanks

https://www.cnblogs.com/fankongkong/p/7339848.html
本文Demo:https://github.com/zj614android/designPattern

猜你喜欢

转载自blog.csdn.net/user11223344abc/article/details/80419177