为什么要使用生产者和消费者模式?
在线程的世界中,生产者就是生产一些数据,而消费者就是把这些数据消费使用,但是他们的速度很可能就是不一致的,有的时候是生产者快有的时候生产者慢而消费者快,就需要有个设计模式去解决这个问题,而不至于一个过快一个过慢
,于是就诞生了生产者消费者模式,这个设计模式实际上把生产方和消费方进行了解耦,从而达到更加流畅的配合。
能解决什么问题?
能解决生产过快消费不足或者生产不足消费过快的问题
,而且能让生产方和消费方之间解耦。
代码演示
数据容器: 用于存储生产出的数据,定义了生产数据的put方法和消费数据的take方法。
- put方法实现逻辑:
首先两个方法都需要同步加锁,防止出现线程安全问题,而且wait也需要monitor锁,需要定义在synchronized修饰的方法里面
。里面的逻辑也很简单,如果storage队列满了,我们就调用wait()等待,不再生产数据。 - take方法实现逻辑:如果队列为空,就调用wait等待。
- notify唤醒逻辑:
- 生产者生产过快的情况:生产者生产过快,storage会处于满的状态,这时候不再生产数据处于等待状态,消费者那边会消费数据,
消费完最后会调用notify方法唤醒生产者继续生产数据
。 - 消费者消费过快的情况:消费者消费过快,storage会处于空的状态,这时候消费者这边检查到没有数据消费就处于等待状态,
生产者那边生产出一条数据后会唤醒消费者继续消费数据
。
- 生产者生产过快的情况:生产者生产过快,storage会处于满的状态,这时候不再生产数据处于等待状态,消费者那边会消费数据,
class EventStorage {
private int maxSize;
private LinkedList<Date> storage;
public EventStorage() {
maxSize = 10;
storage = new LinkedList<>();
}
public synchronized void put() {
while (storage.size() == maxSize) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.println("仓库里有了" + storage.size() + "个产品。");
notify();
}
public synchronized void take() {
while (storage.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("拿到了" + storage.poll() + ",现在仓库还剩下" + storage.size());
notify();
}
}
生产者: 用于生产数据,可以看到,生产者中storage用于存储生产出的数据,run方法用于完成生产数据的任务。
class Producer implements Runnable {
private EventStorage storage;
public Producer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
消费者: 用于消费数据
class Consumer implements Runnable {
private EventStorage storage;
public Consumer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
主类: 启动一个线程生产数据,另一个线程消费数据。
public class ProducerConsumerModel {
public static void main(String[] args) {
EventStorage eventStorage = new EventStorage();
Producer producer = new Producer(eventStorage);
Consumer consumer = new Consumer(eventStorage);
new Thread(producer).start();
new Thread(consumer).start();
}
}
打印结果:
仓库里有了1个产品。
仓库里有了2个产品。
仓库里有了3个产品。
仓库里有了4个产品。
仓库里有了5个产品。
仓库里有了6个产品。
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下5
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下4
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下3
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下2
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下1
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下0
仓库里有了1个产品。
仓库里有了2个产品。
仓库里有了3个产品。
仓库里有了4个产品。
仓库里有了5个产品。
仓库里有了6个产品。
仓库里有了7个产品。
仓库里有了8个产品。
仓库里有了9个产品。
仓库里有了10个产品。
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下9
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下8
拿到了Sat Nov 02 20:33:09 CST 2019,现在仓库还剩下7
...
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》