java中实现生产者-消费者模型需用同一锁对象同步,wait()必须置于while循环中防虚假唤醒,且优先使用notifyall()避免死锁;推荐显式定义final锁对象并用blockingqueue替代手动实现。

在 Java 中,synchronized 与 wait()、notify()(或 notifyAll())配合,是实现经典生产者-消费者模型最基础、最典型的方案。核心在于:所有共享状态操作必须在同一个锁对象上同步,且 wait() 和 notify() 必须在该锁的同步块内调用。
锁对象必须统一
生产者和消费者操作的是同一份共享资源(如一个队列),它们必须使用**同一个对象作为 synchronized 锁**,否则 wait() 和 notify() 将无法跨线程通信。常见错误是各自用 this 或不同对象加锁,导致唤醒失效。
推荐做法:显式定义一个私有 final 对象作为锁,例如:
private final Object lock = new Object();
// 生产者中:
synchronized (lock) { ... }
// 消费者中:
synchronized (lock) { ... }
wait 必须放在 while 循环中判断条件
wait() 会释放锁并挂起当前线程,但被唤醒后不保证条件已满足(可能虚假唤醒,或多个线程竞争后条件又被其他线程改回)。所以绝不能用 if,必须用 while 循环重检条件。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 生产者等待:当缓冲区满时
while (queue.size() == capacity) lock.wait(); - 消费者等待:当缓冲区空时
while (queue.isEmpty()) lock.wait();
notify 应该用 notifyAll 而非 notify
虽然 notify() 只唤醒一个等待线程,看似高效,但在多生产者或多消费者场景下容易引发死锁或饥饿——比如唤醒了一个同类型的线程(如唤醒了另一个生产者,但缓冲区仍满),而真正需要的消费者却一直没被唤醒。
更安全的做法是使用 notifyAll(),让所有等待线程重新竞争锁并检查条件。JVM 会唤醒所有线程,但只有满足条件的那个能继续执行,其余继续 wait()。
完整示意代码片段(简化版)
以下是一个基于 ArrayList 的有界缓冲区示例:
class BoundedBuffer {
private final List<integer> queue = new ArrayList();
private final int capacity = 5;
private final Object lock = new Object();
void produce(int item) throws InterruptedException {
synchronized (lock) {
while (queue.size() == capacity) {
lock.wait(); // 等待有空位
}
queue.add(item);
System.out.println("Produced: " + item + ", size=" + queue.size());
lock.notifyAll(); // 唤醒可能等待消费的线程
}
}
int consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // 等待有数据
}
int item = queue.remove(0);
System.out.println("Consumed: " + item + ", remaining=" + queue.size());
lock.notifyAll(); // 唤醒可能等待生产的线程
return item;
}
}
}
</integer>
注意:实际项目中更推荐使用 java.util.concurrent 包下的线程安全组件(如 BlockingQueue),它们内部已封装好这些细节,更健壮、易用。但理解 synchronized + wait/notify 的协作逻辑,对掌握 Java 并发底层机制至关重要。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










