按照线程的层面,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完才能继续生产数据。如果消费者的处理能力大于生产者,那么消费者必须等待生产者。为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式
生产者消费者模式通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列取。阻塞队列相当于一个缓冲区,平衡了生产者和消费者的处理能力
可以wait、notify、notifyAll 处理生产者消费者问题。例如:生产者线程在缓冲区为满的时候,消费者在缓冲区为空的时候,都应该暂停运行。然后用notify 和notifyAll通知等待中的线程重新开始执行。
notify 仅通知一个线程,且不确定哪个线程会收到通知
notifyAll 会通知所有等待中的线程
示例代码如下:
public class ProducerCOnsumerTest {
@org.junit.Test
public void test() {
//定义缓冲器,及最大数量
int max = 9;
Queue<Integer> buffer = new LinkedList<Integer>();
Consumer consumer = new Consumer(max, buffer);
Producer producer = new Producer(max, buffer);
new Thread(consumer).start();
new Thread(producer).start();
}
}
//生产者
class Producer implements Runnable {
Queue<Integer> buffer;
int max;
public Producer(int max, Queue<Integer> buffer) {
this.max = max;
this.buffer = buffer;
}
@Override
public void run() {
while (true) {
synchronized (buffer) {
while (max == buffer.size()) {
try {
System.out.println("生产队列已满");
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer num = new Random(100).nextInt();
System.out.println("生产:" + num);
buffer.add(num);
buffer.notifyAll();
}
}
}
}
//消费者
class Consumer implements Runnable {
Queue<Integer> buffer;
int max;
public Consumer(int max, Queue<Integer> buffer) {
this.max = max;
this.buffer = buffer;
}
@Override
public void run() {
while (true) {
synchronized (buffer) {
while (buffer.isEmpty()) {
try {
System.out.println("队列已空");
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer num = buffer.remove();
System.out.println("消费:" + num);
buffer.notifyAll();
}
}
}
}
需要注意的地方:
1)可以使用wait 和notify 来实现线程间的通信
2)永远在synchronized 的函数或者对象里使用wait、notify和notifyAll 不然Java虚拟机会生成IIIegalMonitorStateException.
3) 永远在while循环里而不是if语句下使用wait.这样循环会在线程wait 前后都检查条件,并在条件实际上未改变的情况下处理notify
4)永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait.
5)更合适用notifyAll 而不是notify