场景介绍
我们有一个数据缓冲区,一个或者多个生产者把数据存入这个缓冲区,一个或者多个消费者从缓冲区中取出数据
缓冲区中的是共享数据
当缓冲区满的时候不能生产者将不能再放入数据到缓冲区(生产者线程阻塞)
当缓冲区空的时候消费者不能从缓冲区中读取数据(消费者线程阻塞)
实例:
1. 创建数据处理类,其中缓冲区的保存、读取、生产操作
public class EventStorage {
//缓冲区数据的最大值
private int maxSize;
//缓冲区
private List<Date> storage;
public EventStorage() {
maxSize = 10;
storage = new LinkedList<>();
}
//生产方法
public synchronized void set() {
//如果已满就挂起线程
while (storage.size() == maxSize) {
try {
System.out.println("producer wait");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.println("Set : " + storage.size());
//通知等待的线程消费者线程
notifyAll();
}
//消费方法
public synchronized void get() {
//如果没有库存就挂起线程
while (storage.size() == 0) {
try {
System.out.println("consumer wait");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
((LinkedList<?>) storage).poll();
System.out.println("Get : " + storage.size());
//通知阻塞的线程生产者线程
notifyAll();
}
}
2. 创建生产者线程,其构造函数接收一个数据处理对象
public class EventProducer implements Runnable { private EventStorage storage; public EventProducer(EventStorage storage) { this.storage = storage; } @Override public void run() { for (int i = 0; i < 100; i++) { storage.set(); } } }
3.创建消费者线程,也接收同一个数据处理对象
public class EventConsumer implements Runnable { private EventStorage storage; public EventConsumer(EventStorage storage) { this.storage = storage; } @Override public void run() { for (int i = 0; i < 100; i++) { storage.get(); } } }
4.创建测试类
public class TestCP { public static void main(String[] args) { EventStorage storage = new EventStorage(); Thread consumer = new Thread(new EventConsumer(storage)); Thread producer = new Thread(new EventProducer(storage)); consumer.start(); producer.start(); } }
5.运行程序查看控制台输出
可以看到程序输出和预期的结果一样
注意:
1.必须在while()循环内调用wait(),使得线程在达到指定条件后跳出循环等待才继续运行
2.数据处理类的生产和消费方法是synchronized修饰的