java中wait/notify需在synchronized块内使用,配合while循环防虚假唤醒,锁对象须唯一且共享,推荐notifyall避免饥饿,实际开发优先选用blockingqueue。

在 Java 中,wait 和 notify 是 Object 类提供的原生线程通信机制,常用于实现生产者-消费者模型。关键在于:必须在同步块(synchronized)中调用,且需配合条件判断(避免虚假唤醒),同时用 while 而非 if 检查条件。
使用 synchronized 锁定共享资源
生产者和消费者操作的共享缓冲区(如队列)必须被同一把锁保护。通常将锁对象设为缓冲区本身或显式定义的 Object lock = new Object()。所有对缓冲区的读写、wait/notify 都需在该锁的同步块内执行。
- 锁对象必须是所有线程可见且唯一的,不能每次 new 一个新对象
- 推荐直接用
synchronized(buffer),语义清晰,不易出错 - 不要混用
ReentrantLock+wait/notify,它们属于不同机制
用 while 循环检查条件,防止虚假唤醒
wait() 可能被意外唤醒(spurious wakeup),所以不能用 if 判断后直接消费或生产,必须用 while 循环持续校验业务条件是否真正满足。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 生产者:当缓冲区满时
wait(),需while (buffer.size() == MAX_SIZE) - 消费者:当缓冲区空时
wait(),需while (buffer.isEmpty()) - 每次
notifyAll()后,所有等待线程重新竞争锁并再次检查条件
notifyAll 而非 notify,避免线程饥饿
虽然 notify() 只唤醒一个等待线程,但无法保证唤醒的是需要继续执行的那类线程(比如唤醒了另一个生产者,而此时仍满)。用 notifyAll() 更安全,让所有等待线程重新判断自身条件。
- 生产者调用
notifyAll()表示“可能有空间了”,让消费者有机会检查 - 消费者调用
notifyAll()表示“可能有数据了”,让生产者有机会检查 - 性能影响在一般场景下可忽略;若确定只有一个等待者且逻辑严格,才考虑
notify()
典型代码结构示例
以下是一个简化但完整的双线程版(一个生产者 + 一个消费者)核心逻辑:
// 共享缓冲区(简单用 ArrayList 模拟)
List<integer> buffer = new ArrayList();
final int MAX_SIZE = 5;
// 生产者
new Thread(() -> {
int i = 0;
while (true) {
synchronized (buffer) {
while (buffer.size() == MAX_SIZE) {
try { buffer.wait(); } catch (InterruptedException e) { return; }
}
buffer.add(i++);
System.out.println("Produced: " + i);
buffer.notifyAll(); // 唤醒可能等待的消费者
}
try { Thread.sleep(100); } catch (InterruptedException e) { break; }
}
}).start();
// 消费者
new Thread(() -> {
while (true) {
synchronized (buffer) {
while (buffer.isEmpty()) {
try { buffer.wait(); } catch (InterruptedException e) { return; }
}
int item = buffer.remove(0);
System.out.println("Consumed: " + item);
buffer.notifyAll(); // 唤醒可能等待的生产者
}
try { Thread.sleep(150); } catch (InterruptedException e) { break; }
}
}).start();
</integer>
不复杂但容易忽略细节。实际项目中更推荐用 BlockingQueue(如 ArrayBlockingQueue)替代手写,它已封装好线程安全与等待通知逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










