在 Java 中,生产者-消费者模式(Producer-Consumer Pattern)是一种常见的多线程设计模式,通常用于在多线程环境中协调数据生产和消费,以提高程序的吞吐量,并防止生产过快或消费过快导致数据丢失或资源浪费。
实现方式
1. 使用 synchronized
+ wait
+ notify
import java.util.LinkedList;
import java.util.Queue;
class SharedQueue {
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 5;
public synchronized void produce(int value) throws InterruptedException {
while (queue.size() == capacity) {
System.out.println("队列已满,生产者等待...");
wait(); // 释放锁,并等待
}
queue.add(value);
System.out.println("生产:" + value);
notify(); // 唤醒消费者
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
System.out.println("队列为空,消费者等待...");
wait(); // 释放锁,并等待
}
int value = queue.poll();
System.out.println("消费:" + value);
notify(); // 唤醒生产者
return value;
}
}
public class ProducerConsumerSynchronized {
public static void main(String[] args) {
SharedQueue sharedQueue = new SharedQueue();
// 生产者线程
Thread producer = new Thread(() -> {
int value = 0;
try {
while (true) {
sharedQueue.produce(value++);
Thread.sleep(500); // 模拟生产耗时
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
try {
while (true) {
sharedQueue.consume();
Thread.sleep(1000); // 模拟消费耗时
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
解释
- 使用
synchronized
确保线程安全。 - 使用
wait()
让线程在条件不满足时等待(生产者等待队列有空位,消费者等待有数据)。 - 使用
notify()
唤醒对方线程(生产者唤醒消费者,消费者唤醒生产者)。 - 生产和消费在不同的线程中进行,互相协调。
2. 使用 BlockingQueue
(推荐)
BlockingQueue
是 Java 提供的线程安全队列,自动处理线程等待和唤醒,比 synchronized
+ wait/notify
更简洁。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Producer implements Runnable {
private final BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
int value = 0;
try {
while (true) {
queue.put(value);
System.out.println("生产:" + value);
value++;
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
private final BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
int value = queue.take();
System.out.println("消费:" + value);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ProducerConsumerBlockingQueue {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
new Thread(new Producer(queue)).start();
new Thread(new Consumer(queue)).start();
}
}
解释
BlockingQueue
自动管理线程同步,不需要synchronized
。put()
和take()
方法自动阻塞生产者或消费者,避免wait/notify
处理复杂逻辑。
3. 使用 Lock
+ Condition
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 5;
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public void produce(int value) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
System.out.println("队列已满,生产者等待...");
notFull.await();
}
queue.add(value);
System.out.println("生产:" + value);
notEmpty.signal(); // 唤醒消费者
} finally {
lock.unlock();
}
}
public int consume() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
System.out.println("队列为空,消费者等待...");
notEmpty.await();
}
int value = queue.poll();
System.out.println("消费:" + value);
notFull.signal(); // 唤醒生产者
return value;
} finally {
lock.unlock();
}
}
}
public class ProducerConsumerLock {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
int value = 0;
try {
while (true) {
resource.produce(value++);
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
while (true) {
resource.consume();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
解释
ReentrantLock
提供更灵活的锁机制。Condition
代替wait/notify
,更清晰地控制线程等待和唤醒。
总结
方法 | 线程安全 | 代码简洁性 | 适用场景 |
---|---|---|---|
synchronized + wait/notify |
是 | 一般 | 适用于小规模同步需求 |
BlockingQueue |
是 | 最佳 | 推荐,代码简单、性能高 |
Lock + Condition |
是 | 一般 | 适用于更复杂的同步控制 |