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

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,存量不足,不能消费!

  

 

  

时间: 2024-11-05 16:04:52

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

java 多线程并发系列之 生产者消费者模式的两种实现

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生

生产者消费者模式的三种实现方式

synchronized版本 public class Test { public static void main(String[] args) { Shared s = new Shared(); Thread t1 = new Thread(new Product(s)); Thread t2 = new Thread(new Consumer(s)); t1.start(); t2.start(); } } class Product implements Runnable { priv

Linux:生产者与消费者模式

生产者:生产数据 消费者:消费数据 提供场所:缓冲区,eg:超市 生产者消费者特点:三种关系,两类人,一个场所 三种关系指的是:生产者与生产者之间是互斥关系 消费者与消费者之间是互斥关系 生产者与消费者之间是同步与互斥关系 两类人:生产者,消费者 一个场所:存储数据(此处用带头单链表实现) 单生产者单消费者模式:此例取数据方式为FIFO先进先出. 利用互斥锁实现单生产者单消费者模式. #include<stdio.h> #include<malloc.h> #include<

生产者与消费者模式(线程的同步与互斥)

死锁产生的四个条件: 1.互斥使用(资源独占) 一个资源每次只能给一个进程使用 .2.不可强占(不可剥夺) 资源申请者不能强行的从资源占有者手中夺取资源,资源只能由占有者自愿释放 .3.请求和保持(部分分配,占有申请) 一个进程在申请新的资源的同时保持对原有资源的占有(只有这样才是动态申请,动态分配) .4.循环等待 存在一个进程等待队列 {P1 , P2 , - , Pn}, 其中P1等待P2占有的资源,P2等待P3占有的资源,-,Pn等待P1占有的资源,形成一个进程等待环路 生产者:生产数据

Java多线程-----实现生产者消费者模式的几种方式

   1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理, 直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.这个阻塞队列就是用来给生产者和消费者解耦的. 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度

多线程生产者、消费者模式中,如何停止消费者?多生产者情况下对“毒丸”策略的应用。

生产者.消费者模式是多线程中的经典问题.通过中间的缓冲队列,使得生产者和消费者的速度可以相互调节. 对于比较常见的单生产者.多消费者的情况,主要有以下两种策略: 通过volatile boolean producerDone =false 来标示是否完成.生产者结束后标示为true, 消费者轮询这个变量来决定自己是否退出. 这种方式对producerDone产生比较大的争用,实现起来也有诸多问题需要考虑. 比较经典的"毒丸"策略,生产者结束后,把一个特别的对象:"毒丸&quo

Java多线程设计模式(2)生产者与消费者模式

1 Producer-Consumer Pattern Producer-Consumer Pattern主要就是在生产者与消费者之间建立一个“桥梁参与者”,用来解决生产者线程与消费者线程之间速度的不匹配. 当要从某个线程Produccer参与者将数据传输给其它线程Consumer参与者的时候,此时就可以在中间加一个Channel参与者,在Channel参与者中以某种方式存放接受的数据,再以某方式来获取收到的数据,Channel就可以来缓存两个线程之间传输的数据,在Channel参与者为了保证安

Java并发编程(4)--生产者与消费者模式介绍

一.前言 这种模式在生活是最常见的,那么它的场景是什么样的呢? 下面是我假象的,假设有一个仓库,仓库有一个生产者和一个消费者,消费者过来消费的时候会检测仓库中是否有库存,如果没有了则等待生产,如果有就先消费直至消费完成:而生产者每天的工作就是先检测仓库是否有库存,如果没有就开始生产,满仓了就停止生产等待消费,直至工作结束.下图是根据假象画的流程图: 那么在程序中怎么才能达到这样的效果呢?下面介绍三种方式实现. 二.使用notify() 和 wait()实现 相信大家这两个方法都不陌生,它是Obj

实现生产者与消费者模式

实现生产者与消费者模式 目录 生产者与消费者模式 实现 生产者与消费者模式 什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力. 这个阻塞队列就是用来给生产者和消费者解耦的.纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式