1.模式定义
生产者-消费者模式是一个经典的多线程设计模式。它为多线程间的协作提供了良好的解决方案。在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程。生产者线程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务。生产者和消费者之间则通过共享内存缓冲区进行通信。

图5.1 展示了生产者-消费者模式的基本结构。
三个生产者线程将任务提交到共享内存缓冲区,消费者线程并不直接与生产者线程通信,而在共享内存缓冲区中获取任务,并进行处理。
注意:生产者-消费者模式中的内存缓存区的主要功能是数据在多线程间的共享,此外,通过该缓冲区,可以缓解生产者和消费者间的性能差生产者-消费者模式的核心组件是共享内存缓存区,它作为生产者和消费者间的通信桥梁避免了生产者和消费者的直接通信,从而将生产者和消费者进行解耦。生产者不需要知道消费者的存在,消费者也不需要知道生产者的存在。
同时,由于内存缓冲区的存在,允许生产者和消费者在执行速度上存在时间差,无论是生产者在某一局部时间内速度高于消费者,还是消费者在局部时间内高于生产者,都可以通过共享内存缓冲区得到缓解,确保系统正常运行
2.程序代码
package com.john.learn.high.concurent.ch04.queue;
public class QueueMessage {
private final int radius;
private final int messageId;
public QueueMessage(int messageId, int radius) {
this.radius =radius;
this.messageId = messageId;
}
public int getMessageId() {
return messageId;
}
public int getRadius() {
return radius;
}
@Override
public String toString() {
return "Id:" + this.messageId +" Radius:" + this.radius;
}
}
package com.john.learn.high.concurent.ch04.queue;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class MessageProducer implements Runnable {
private volatile boolean stop = false;
private BlockingQueue<QueueMessage> blockingQueue;
private static final int SLEEP_TIME = 1000;
private static final AtomicInteger QueueCount = new AtomicInteger();
private Random random;
public MessageProducer(BlockingQueue<QueueMessage> blockingQueue) {
this.blockingQueue = blockingQueue;
random = new Random();
}
@Override
public void run() {
try {
while (!this.stop) {
Thread.sleep(random.nextInt(SLEEP_TIME));
QueueMessage queueMessage = new QueueMessage(QueueCount.incrementAndGet(), random.nextInt(SLEEP_TIME));
if (!blockingQueue.offer(queueMessage, 2, TimeUnit.SECONDS)) {
System.out.println("Failed to put data:" + queueMessage);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
this.stop = true;
}
}
public void stop() {
this.stop = true;
}
}
package com.john.learn.high.concurent.ch04.queue;
import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
public class MessageConsumer implements Runnable {
public MessageConsumer(BlockingQueue<QueueMessage> blockingQueue) {
this.blockingQueue = blockingQueue;
random = new Random();
}
@Override
public void run() {
try {
while (true) {
QueueMessage queueMessage = this.blockingQueue.take();
if (queueMessage == null) {
continue;
}
System.out.println(MessageFormat.format("Req Id{0}:{1}*{2}={3}", queueMessage.getMessageId(),
queueMessage.getRadius(), queueMessage.getRadius(),
(int) Math.pow(queueMessage.getRadius(), 2)));
Thread.sleep(SLEEP_TIME);
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
private BlockingQueue<QueueMessage> blockingQueue;
private Random random;
private static final int SLEEP_TIME = 1000;
}
package com.john.learn.high.concurent.ch04.queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class QueueMessageMain {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
BlockingQueue<QueueMessage> blockingQueue = new ArrayBlockingQueue<>(10);
MessageProducer messageProducer = new MessageProducer(blockingQueue);
new Thread(messageProducer).start();
new Thread(messageProducer).start();
new Thread(messageProducer).start();
MessageConsumer messageConsumer = new MessageConsumer(blockingQueue);
executorService.submit(messageConsumer);
Thread.sleep(5000);
messageProducer.stop();
executorService.shutdown();
Thread.sleep(3000);
executorService.shutdownNow();
}
}