1. 原理
它描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者可以从仓库中取走产品,解决生产者/消费者问题,我们需要采用某种机制保护生产者和消费者之间的同步
同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性,常用的方法就是加锁,保证资源在任意时刻只被一个线程访问
画图分析:
2. 实现
采用wait()、notify()和notifyAll()方法
wait():当缓冲区已满或空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行
·是Object的方法
·调用方式:对象.wait();
·表示释放 对象 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)
·等待,必须放到同步代码段中执行
notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态
·是Object的方法
·调用方式:对象.notify();
·表示唤醒 对象 所标记外边在等待的一个线程
notifyAll():全部唤醒
·是Object的方法
·调用方式:对象.notifyAll()
·表示唤醒 对象 所标记外边等待的所有线程
代码实现:
/**
* @author bruceliu
* @create 2019-06-01 22:04
* @description
*/
public class ProductorAndConsumerDemo01 {
// 定义一个标记,用来表示产品是否需要被生产
static boolean shouldProduct = true;
static Object o=new Object();
// 静态成员内部类
// 生产者线程的target
static class Productor implements Runnable {
//需要生产的产品
private Product p;
public Productor(Product p) {
this.p = p;
}
public void run() {
while (true) {
synchronized (o) {
if (shouldProduct) {
//生产
this.p.setName("老婆饼");
System.out.println("生产者" + Thread.currentThread().getName() + "生产了一件产品" + this.p);
//修改状态
shouldProduct = false;
//通知消费者来进行消费
o.notifyAll();
} else {
//等待
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
//消费者线程的target
static class Consumer implements Runnable {
//需要被消费的产品
private Product p;
public Consumer(Product p) {
this.p = p;
}
public void run() {
while (true) {
synchronized (o) {
if (shouldProduct) {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
//消费
System.out.println("消费者" + Thread.currentThread().getName() + "消费了一件产品" + this.p);
//修改状态
shouldProduct = true;
//通知生产者去生产
o.notifyAll();
}
}
}
}
}
public static void main(String[] args) {
//说明:如果锁外面只有一个生产者或者一个消费者等待的话,则使用notify唤醒,
//但是,如果锁外面有多个生产者或者多个消费者等待的话,则使用notifyAll唤醒
//实例化一个产品
Product p = new Product();
//生产者
Productor productor = new Productor(p);
Thread t0 = new Thread(productor,"老王头");
Thread t1 = new Thread(productor,"老李头");
t0.start();
t1.start();
//消费者
Consumer consumer = new Consumer(p);
Thread thread0 = new Thread(consumer,"小凳子");
Thread thread1 = new Thread(consumer,"小桌子");
thread0.start();
thread1.start();
}
}
class Product {
private String name;
private int id;
public void setName(String name) {
this.name = name;
id++;
}
public String toString() {
return "Product [name=" + name + ", id=" + id + "]";
}
}