关于生产者与消费者模式的两种实现方式

Posted hunter_Cecil

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于生产者与消费者模式的两种实现方式相关的知识,希望对你有一定的参考价值。

1、wait & notify 方法:

public class WaitAndNotify {
    private final int MAX_SIZE = 100;
    private LinkedList<Object> list = new LinkedList<Object>();

    public void produce(int num)
    {
        synchronized (list)
        {
            while (list.size() + num > MAX_SIZE)
            {
                System.out.println("要生产的产品数:" + num + ", 现库存量为:"
                        + list.size() + " 不能继续生产!");
                try
                {
                    list.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }

            for (int i = 1; i <= num; ++i)
            {
                list.add(new Object());
                System.out.println("已生产产品数:" + num + ", 现产品量为:" + list.size());
            }
            list.notifyAll();
        }
    }

    public void consume(int num)
    {
        synchronized (list)
        {
            while (list.size() < num)
            {
                System.out.println("要消费的产品量:" + num + ", 现库存量为:"
                        + list.size() + ",存量不足,暂时不能消费!");
                try
                {
                    list.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }

            for (int i = 1; i <= num; ++i)
            {
                list.remove();
                System.out.println("已消费产品数" + num + ", 现存量为:" + list.size());
            }
            list.notifyAll();
        }
    }
}

public class Producer implements Runnable{
    private int num;
    private WaitAndNotify storage;

    public Producer(WaitAndNotify storage)
    {
        this.storage = storage;
    }

    public void run()
    {
        produce(num);
    }

    public void produce(int num)
    {
        storage.produce(num);
    }

    public int getNum()
    {
        return num;
    }

    public void setNum(int num)
    {
        this.num = num;
    }

    public WaitAndNotify getStorage()
    {
        return storage;
    }

    public void setStorage(WaitAndNotify storage)
    {
        this.storage = storage;
    }
}

public class Consumer implements Runnable{
    private int num;
    private WaitAndNotify storage;

    public Consumer(WaitAndNotify storage)
    {
        this.storage = storage;
    }

    public void run()
    {
        consume(num);
    }

    public void consume(int num)
    {
        storage.consume(num);
    }

    public int getNum()
    {
        return num;
    }

    public void setNum(int num)
    {
        this.num = num;
    }

    public WaitAndNotify getStorage()
    {
        return storage;
    }

    public void setStorage(WaitAndNotify storage)
    {
        this.storage = storage;
    }
}

public class WaitAndNotifyTest {
    public static void main(String[] args) {
        WaitAndNotify storage = new WaitAndNotify();

        Producer p1 = new Producer(storage);
        Producer p2 = new Producer(storage);
        Producer p3 = new Producer(storage);
        p1.setNum(10);
        p2.setNum(20);
        p3.setNum(30);

        Consumer c1 = new Consumer(storage);
        Consumer c2 = new Consumer(storage);
        c1.setNum(15);
        c2.setNum(20);

        p1.run();
        p2.run();
        c1.run();
        c2.run();
        p3.run();
    }
}

 运行结果如下:

已生产产品数:10, 现产品量为:1
已生产产品数:10, 现产品量为:2
已生产产品数:10, 现产品量为:3
已生产产品数:10, 现产品量为:4
已生产产品数:10, 现产品量为:5
已生产产品数:10, 现产品量为:6
已生产产品数:10, 现产品量为:7
已生产产品数:10, 现产品量为:8
已生产产品数:10, 现产品量为:9
已生产产品数:10, 现产品量为:10
已生产产品数:20, 现产品量为:11
已生产产品数:20, 现产品量为:12
已生产产品数:20, 现产品量为:13
已生产产品数:20, 现产品量为:14
已生产产品数:20, 现产品量为:15
已生产产品数:20, 现产品量为:16
已生产产品数:20, 现产品量为:17
已生产产品数:20, 现产品量为:18
已生产产品数:20, 现产品量为:19
已生产产品数:20, 现产品量为:20
已生产产品数:20, 现产品量为:21
已生产产品数:20, 现产品量为:22
已生产产品数:20, 现产品量为:23
已生产产品数:20, 现产品量为:24
已生产产品数:20, 现产品量为:25
已生产产品数:20, 现产品量为:26
已生产产品数:20, 现产品量为:27
已生产产品数:20, 现产品量为:28
已生产产品数:20, 现产品量为:29
已生产产品数:20, 现产品量为:30
已消费产品数15, 现存量为:29
已消费产品数15, 现存量为:28
已消费产品数15, 现存量为:27
已消费产品数15, 现存量为:26
已消费产品数15, 现存量为:25
已消费产品数15, 现存量为:24
已消费产品数15, 现存量为:23
已消费产品数15, 现存量为:22
已消费产品数15, 现存量为:21
已消费产品数15, 现存量为:20
已消费产品数15, 现存量为:19
已消费产品数15, 现存量为:18
已消费产品数15, 现存量为:17
已消费产品数15, 现存量为:16
已消费产品数15, 现存量为:15
要消费的产品量:20, 现库存量为:15,存量不足,暂时不能消费!

   这里有个问题:为了唤醒正在等待的线程,应该使用notify还是notifyAll?

  一般情况下,应该使用notifyAll,这是合理而保守的建议,它总会产生正确的结果,因为它可以保证将会唤醒所有需要被唤醒的线程。可能会唤醒一些其他的线程,但这不会影响程序的正确性,这些线程醒来之后,会检查他们正在等待的条件,如果发现条件并不满足,就会继续等待。
  
从优化的角度来讲,如果处于等待状态的所有线程都在等待同一个条件,而每次只有一个线程可以从这个条件被唤醒,那么就应该选择notify,而不是notifyAll。
  

2、BlockingQueue方法:

  直接使用wait和notify就像用“并发编程语言”进行编程一样,而java.util.concurrent则提供了更高级的语言,没有理由在新代码中使用wait和notify.即使有,也是极少的。下面我们对比一下阻塞队列方法BlockingQueue,它是java.util.concurrent下的主要用来控制线程同步的工具。

public class BlockingQueue
{
    private final int MAX_SIZE = 100;
    private LinkedBlockingQueue<Object> productList = new LinkedBlockingQueue<Object>(100);

    public void Produce(int num)
    {
        if (productList.size() == MAX_SIZE)
        {
            System.out.println("生产库存量为:" + MAX_SIZE + ",库存已满,暂时无法生产!");
        }
        for (int i = 1; i <= num; ++i)
        {
            try
            {
                productList.put(new Object());
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println("生产库存量为:" + productList.size());
        }
    }

    public void Consume(int num)
    {
        if (productList.size() == 0)
        {
            System.out.println("消费库存量为0,暂时不能消费!");
        }
        for (int i = 1; i <= num; ++i)
        {
            if (productList.size() < num)
            {
                System.out.println(
                        "要消费的产品量:" + num + ", 现库存量为:" + productList.size() + ",存量不足,不能消费!");
            }
            try
            {
                productList.take();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        System.out.println("消费库存量:" + productList.size());
    }
}

public class Producer implements Runnable {
    private int num;
    private BlockingQueue storage;

    public Producer(BlockingQueue storage)
    {
        this.storage = storage;
    }

    public void run()
    {
        produce(num);
    }

    public void produce(int num)
    {
        storage.Produce(num);
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public BlockingQueue getStorage() {
        return storage;
    }

    public void setStorage(BlockingQueue storage) {
        this.storage = storage;
    }
}

public class Consumer implements Runnable{
    private int num;
    private BlockingQueue storage;

    public Consumer(BlockingQueue storage)
    {
        this.storage = storage;
    }

    public void run()
    {
        consume(num);
    }

    public void consume(int num)
    {
        storage.Consume(num);
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public BlockingQueue getStorage() {
        return storage;
    }

    public void setStorage(BlockingQueue storage) {
        this.storage = storage;
    }
}

public class BlockingQueueTest {
    public static void main(String[] args) {
        BlockingQueue storage = new BlockingQueue();

        Producer p1 = new Producer(storage);
        Producer p2 = new Producer(storage);
        Producer p3 = new Producer(storage);
        p1.setNum(10);
        p2.setNum(20);
        p3.setNum(30);

        Consumer c1 = new Consumer(storage);
        Consumer c2 = new Consumer(storage);
        c1.setNum(15);
        c2.setNum(20);

        p1.run();
        p2.run();
        c1.run();
        c2.run();
        p3.run();
    }
}

  运行结果如下:

生产库存量为:1
生产库存量为:2
生产库存量为:3
生产库存量为:4
生产库存量为:5
生产库存量为:6
生产库存量为:7
生产库存量为:8
生产库存量为:9
生产库存量为:10
生产库存量为:11
生产库存量为:12
生产库存量为:13
生产库存量为:14
生产库存量为:15
生产库存量为:16
生产库存量为:17
生产库存量为:18
生产库存量为:19
生产库存量为:20
生产库存量为:21
生产库存量为:22
生产库存量为:23
生产库存量为:24
生产库存量为:25
生产库存量为:26
生产库存量为:27
生产库存量为:28
生产库存量为:29
生产库存量为:30
消费库存量:15
要消费的产品量:20, 现库存量为:15,存量不足,不能消费!
要消费的产品量:20, 现库存量为:14,存量不足,不能消费!
要消费的产品量:20, 现库存量为:13,存量不足,不能消费!
要消费的产品量:20, 现库存量为:12,存量不足,不能消费!
要消费的产品量:20, 现库存量为:11,存量不足,不能消费!
要消费的产品量:20, 现库存量为:10,存量不足,不能消费!
要消费的产品量:20, 现库存量为:9,存量不足,不能消费!
要消费的产品量:20, 现库存量为:8,存量不足,不能消费!
要消费的产品量:20, 现库存量为:7,存量不足,不能消费!
要消费的产品量:20, 现库存量为:6,存量不足,不能消费!
要消费的产品量:20, 现库存量为:5,存量不足,不能消费!
要消费的产品量:20, 现库存量为:4,存量不足,不能消费!
要消费的产品量:20, 现库存量为:3,存量不足,不能消费!
要消费的产品量:20, 现库存量为:2,存量不足,不能消费!
要消费的产品量:20, 现库存量为:1,存量不足,不能消费!
要消费的产品量:20, 现库存量为:0,存量不足,不能消费!

  

 

  

以上是关于关于生产者与消费者模式的两种实现方式的主要内容,如果未能解决你的问题,请参考以下文章

开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型

线程间协作的两种方式

多线程之线程间协作的两种方式:waitnotifynotifyAll和Condition

C++实现 生产者消费者模型

Java并发编程:线程间协作的两种方式:waitnotifynotifyAll和Condition

多线程生产者消费者模型