生产者-消费者模式是一个十分经典的多线程并发协作的模式,它是对现实生活中的生产者、消费者的一种抽象。当我们买奶茶的时候一般都是在收银台下单、取奶茶,奶茶店的收银系统会通知店员制作奶茶。
在生产者-消费者模式中,主要是涉及两类线程,一种是生产者线程用于生产数据,另一种是消费者线程用于消费数据。为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。这就达到了“解耦”的目的。
但是,这个共享数据区域中应该具备这样的线程间并发协作的功能:
1、如果共享数据区已满的话,阻塞生产者继续生产数据放置入内;
2、如果共享数据区为空的话,阻塞消费者继续消费数据;
示例:
生产者线程:
public class ProducerThread implements Runnable {
private MyBlockingQueue myBlockingQueue;
public ProducerThread(MyBlockingQueue myBlockingQueue) {
this.myBlockingQueue = myBlockingQueue;
}
@Override
public void run() {
for (int i = 0;i < 5;i++) {
myBlockingQueue.put(1);
}
}
}
消费者线程:
public class ConsumerThread implements Runnable {
private MyBlockingQueue myBlockingQueue;
public ConsumerThread(MyBlockingQueue myBlockingQueue) {
this.myBlockingQueue = myBlockingQueue;
}
@Override
public void run() {
for (int i = 0;i < 5;i++) {
myBlockingQueue.take();
}
}
}
共享数据区:
public class MyBlockingQueue {
private int[] arr = new int[5];
private volatile int index = 0;
public MyBlockingQueue() {
for (int i = 0;i < arr.length;i++) {
arr[i] = -1;
}
}
public synchronized void put(int i) {
while(isFull()) {
try {
System.out.println("生产者等待!");
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
arr[index] = i;
System.out.println("生产了" + index + "号奶茶");
index++;
notifyAll();
}
public synchronized int take() {
while (isNull()) {
try {
System.out.println("消费者等待!");
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int i = 0;
index--;
i = arr[index];
arr[index] = -1;
System.out.println("消费了" + index + "号奶茶");
notifyAll();
return i;
}
public int getIndex() {
return index;
}
public int size() {
return arr.length;
}
public boolean isFull() {
if(getIndex() == size()) {
return true;
}
return false;
}
public boolean isNull() {
if(getIndex() == 0) {
return true;
}
return false;
}
}
运行结果: