生产/消费者问题涉及到的对象包括生产者、消费者、仓库和产品。他们之间的关系如下:
-
生产者仅仅在仓储未满时候生产,仓满则停止生产。
-
消费者仅仅在仓储有产品时候才能消费,仓空则等待。
-
当消费者发现仓库没产品可消费时候会通知生产者生产。
-
生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。
//可以理解为临界资源,实际上用于存储生产或者消费的对象
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的时间片白白等在那边。有了生产者/消费者模型,生产者和消费者就是两个独立的并发体,生产者把生产出来的数据往缓冲区一丢就好了,不必管消费者;消费者也是,从缓冲区去拿数据就好了,也不必管生产者,缓冲区满了就不生产,缓冲区空了就不消费,使生产者/消费者的处理能力达到一个动态的平衡。
生产者/消费者模式的作用
-
支持并发
-
解耦
-
支持忙闲不均