Java 生产者消费者模式

生产/消费者问题涉及到的对象包括生产者、消费者、仓库和产品。他们之间的关系如下:

  • 生产者仅仅在仓储未满时候生产,仓满则停止生产。

  • 消费者仅仅在仓储有产品时候才能消费,仓空则等待。

  • 当消费者发现仓库没产品可消费时候会通知生产者生产。

  • 生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。

//可以理解为临界资源,实际上用于存储生产或者消费的对象
public class Basket {
    private volatile Object obj;//生产或者消费的对象,使用volatile用于保证可见性
    //定义生产的方法  synchronized用于实现生产和消费不会同时运行
    public synchronized void produce(Object obj){
        //生产者可以生产的前提是obj为空,否则生产者阻塞
        while(this.obj!=null){  //使用循环的目的在于:如果生产者被错误的时间点上唤醒,还需要继续等待
            try {
                this.wait();  //this必须是锁对象,否则异常
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.obj=obj;//接收生产者提交的数据
        this.notifyAll();  //唤醒所有等待阻塞的线程,不区分生产还是消费
        System.out.println("生产了一个对象:"+obj);
    }
    //定义消费方法
    public synchronized void consume(){
        while(this.obj==null){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费了一个对象:"+obj);
        this.obj=null;
        this.notifyAll();
    }
}

定义生产数据的生产者线程

public class Producer implements Runnable{
    private Basket basket; 
    public Producer(Basket basket){   //使用构造器实现由调用者负责保证生产者和消费者使用同一个Basket对象
        this.basket=basket;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            Object obj=new Date();
            basket.produce(obj);
        }
    }
}

定义消费数据的消费者线程

public class Consumer implements Runnable{
    private Basket basket;
    public Consumer(Basket basket){ //使用构造器实现由调用者负责保证生产者和消费者使用同一个Basket对象
        this.basket=basket;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            basket.consume();
        }
    }
}

测试程序:

public class Test {
    public static void main(String[] args) {
        Basket resource = new Basket();
        new Thread(new Producer(resource)).start();
        new Thread(new Consumer(resource)).start();
    }
}
为什么要使用生产者/消费者模式

        在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式。

生产者/消费者模型优点

1、解耦。因为多了一个缓冲区,所以生产者和消费者并不直接相互调用,这一点很容易想到,这样生产者和消费者的代码发生变化,都不会对对方产生影响,这样其实就把生产者和消费者之间的强耦合解开,变为了生产者和缓冲区/消费者和缓冲区之间的弱耦合。

2、通过平衡生产者和消费者的处理能力来提高整体处理数据的速度【反压机制】,这是生产者/消费者模型最重要的一个优点。如果消费者直接从生产者这里拿数据,如果生产者生产的速度很慢,但消费者消费的速度很快,那消费者就得占用CPU的时间片白白等在那边。有了生产者/消费者模型,生产者和消费者就是两个独立的并发体,生产者把生产出来的数据往缓冲区一丢就好了,不必管消费者;消费者也是,从缓冲区去拿数据就好了,也不必管生产者,缓冲区满了就不生产,缓冲区空了就不消费,使生产者/消费者的处理能力达到一个动态的平衡。

生产者/消费者模式的作用
  • 支持并发

  • 解耦

  • 支持忙闲不均

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值