消费者和生产者模式
是用来描述一个仓库(缓冲区),生产者可以将产品放入到仓库中,消费者可以从仓库中买走商品,解决生产者和消费者的生活逻辑问题,需要采用代码的同步机制来完成相互的【约束】和【提醒】。
注意事项
- 【商品是唯一共享资源】
- 消费者购买商品,清空商品的库存,要【提醒】生产者生产,并且消费者停止购买
- 生产者生产商品,填满商品的库存,要【提醒】消费者购买(到货通知),并且生产者是要停止生产操作
实现方法
采用wait()、notify()和notifyAll()方法。
wait():当缓冲区已满或空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行
- 是Object的方法
- 调用方式:对象.wait();
- 表示释放 对象 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)
- 等待,必须放到同步代码段中执行
notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态
- 是Object的方法
- 调用方式:对象.notify();
- 表示唤醒 对象 所标记外边在等待的一个线程,或者从多个待唤醒线程中随机唤醒一个
notifyAll():全部唤醒
- 是Object的方法
- 调用方式:对象.notifyAll()
- 表示唤醒 对象 所标记外边等待的所有线程
案例
生产者生产面包,消费者消费面包,要求仓库有面包时,提醒消费者消费,生产者出于等待状态;当没有面包的时候,提醒生产者生产,消费者处于等待。即生产一件,消费一件。
基本思路:
- 创建面包类,构建相关的属性和方法。
- 创建面包仓库类,面包类对象传入,并创建sychronized修饰的同步方法——input和output方法。
- 创建两个线程,生产者product和消费者consumer,分别继承Runnable,重写run()方法,并分别调用input和output方法,保证同步。
- 在主方法创建Thread,并start。
/**
* 面包类
*/
public class Bread {
private int id;
private String productName;
public Bread() {
}
public Bread(int id, String productName) {
this.id = id;
this.productName = productName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
/**
* 面包容器类
*/
public class BreadCon {
private Bread con;
private boolean flag = false; //判断仓库是否有面包,false表示没有
public synchronized void input(Bread b) throws InterruptedException {
if (flag) {
this.wait(); //如果仓库有面包,则处于阻塞状态,等待消费者消费后唤醒
}
this.con = b;
System.out.println(Thread.currentThread().getName() + "生产了"
+ b.getId() + "号面包");
flag = true;
this.notify(); //仓库没有面包,则生产面包,并将标记改为true,唤醒消费者购买
}
public synchronized void output() throws InterruptedException {
if (!flag) {
this.wait();
}
Bread b= con;
con = null;
System.out.println(Thread.currentThread().getName()+"消费了"
+b.getId() + "号面包" +" 生产者:"+b.getProductName());
flag = false; //修改标记
this.notify(); //唤醒生产者生产
}
}
/**
* 生产者类
*/
public class Product implements Runnable{
private BreadCon con;
public Product(BreadCon con) {
this.con = con;
}
@Override
public void run() {
for (i
版权声明:本文为qq_45337431原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。