生产者-消费者问题
生产者-消费者模式
- 生产者:只关心消息队列满没满,如果消息队列满了,就阻塞等待消费者take()操作,否则生产者进行put()操作往队列中添加消息,消息队列的容量capacity - 1。
- 消费者:只关心消息队列有没有消息,如果消息队列没有有,就阻塞等待生产者put()操作,否则消费者进行take()操作往队列中取出消息,消息队列的容量capacity + 1。
消费队列可以用来平衡生产和消费的线程资源。

实现方式:
- 使用LinkedList和synchronized实现消息队列存放消息。
- 使用Executors.newFixedThreadPool中的创建线程池的方法模拟生产者和消费者线程。
class MessageQueue<V> {
private LinkedList<V> queue = new LinkedList<>();
private int capacity;
public MessageQueue(int capacity) {
this.capacity = capacity;
}
public V get() {
synchronized (this) {
//队列为空,消费者需要等待
String currName = Thread.currentThread().getName();
while (queue.isEmpty()) {
System.out.println(currName + " 队列为空,消费者线程等待。。。。");
//暂停毫秒
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
queue.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//队列不空,消费者消费消息
V message = queue.removeFirst();
//打印消费的信息
System.out.println(currName + " 消费了消息:" + message.toString());
//唤醒其他阻塞线程
queue.notifyAll();
return message;
}
}
public void put(V msg) {
synchronized (this) {
while (true) {
//队列已满,生产者不能放入消息
while (queue.size() == capacity) {
System.out.println(Thread.currentThread().getName() + " 队列已满,生产者线程等待");
try {
queue.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//否则,放入队列
queue.addLast(msg);
//打印生产的消息
System.out.println(Thread.currentThread().getName() + " 生产消息:" + msg.toString());
queue.notifyAll();
}
}
}
}
class Message {
private int id;
private String value;
public Message(int id, String value) {
this.id = id;
this.value = value;
}
@Override
public String toString() {
return "Message{" +
"id=" + id +
", value='" + value + '\'' +
'}';
}
}
public class ProducerAndConsumer1 {
public static void main(String[] args) {
MessageQueue<Message> queue = new MessageQueue<Message>(3);
//创建2个生产者线程
ExecutorService producer = Executors.newFixedThreadPool(2, new ThreadFactory() {
private AtomicInteger id = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "生产者-" + id.getAndIncrement());
}
});
//创建3个消费者线程
ExecutorService consumer = Executors.newFixedThreadPool(3, new ThreadFactory() {
private AtomicInteger id = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "消费者-" + id.getAndIncrement());
}
});
for (int i = 0; i < 10; i++) {
producer.submit(() -> {
int id = new Random().nextInt(20);
queue.put(new Message(id, "" + id));
});
}
for (; ; ) {
consumer.submit(() -> {
queue.get();
});
}
}
}

实现方式:
- 使用阻塞队列(LinkedBlockingQueue)实现消息队列存放消息。
- 使用Executors.newFixedThreadPool中的创建线程池的方法模拟生产者和消费者线程。
class Producer implements Runnable {
private BlockingQueue queue;
public Producer(BlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
int i = new Random().nextInt(50);
String currName = Thread.currentThread().getName();
//暂停毫秒
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
queue.put(i);
System.out.println("生产者线程-" + currName + " 生产了数据:" + i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class Consumer implements Runnable {
private BlockingQueue queue;
public Consumer(BlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
//暂停毫秒
try {
TimeUnit.MILLISECONDS.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
String currName = Thread.currentThread().getName();
try {
int data = (int) queue.take();
System.out.println("消费者线程-" + currName + " 消费了:" + data);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
ExecutorService pool = Executors.newFixedThreadPool(5);
Producer p1 = new Producer(queue);
Producer p2 = new Producer(queue);
Producer p3 = new Producer(queue);
Consumer c1 = new Consumer(queue);
Consumer c2 = new Consumer(queue);
pool.execute(p1);
pool.execute(p2);
pool.execute(p3);
pool.execute(c1);
pool.execute(c2);
pool.shutdown();
}

本文介绍了使用LinkedList和synchronized关键字以及BlockingQueue实现生产者-消费者模型。在第一个实现中,生产者和消费者线程通过自定义的消息队列交互,当队列满或空时,线程会进行等待和唤醒操作。第二个实现则利用阻塞队列LinkedBlockingQueue,简化了同步处理,线程在队列满或空时会自动阻塞。两种方法都通过ExecutorService创建线程池来模拟多个生产者和消费者。


被折叠的 条评论
为什么被折叠?



