notify() 并非 Java 同步机制的自动组成部分,它仅在配合 wait() 实现线程间协作式等待时才有意义;单纯使用 synchronized 块时,JVM 会自动管理锁的获取与释放,无需也不应调用 notify()。
`notify()` 并非 java 同步机制的自动组成部分,它仅在配合 `wait()` 实现线程间协作式等待时才有意义;单纯使用 `synchronized` 块时,jvm 会自动管理锁的获取与释放,无需也不应调用 `notify()`。
在 Java 多线程编程中,初学者常误以为 synchronized 的“等待”行为依赖于 notify() —— 实际上这是一种根本性误解。synchronized 关键字本身已完整封装了互斥访问 + 自动唤醒语义:当一个线程退出同步块(或方法)时,JVM 会自动释放其持有的监视器锁(monitor),并唤醒任意一个因争抢该锁而处于 BLOCKED 状态的线程(注意:不是 WAITING 状态)。这个过程完全由 JVM 底层调度完成,与 notify()/notifyAll() 无关。
✅ 正确理解线程状态与锁生命周期
| 线程状态 | 触发条件 | 锁是否持有 | 是否需要 notify() |
|---|---|---|---|
| BLOCKED | 尝试进入已被占用的 synchronized 块 | 否 | ❌ 不需要 |
| WAITING | 在同步块内调用 wait() | ❌ 已释放 | ✅ 必须由其他线程 notify() 唤醒 |
| TIMED_WAITING | 调用 wait(long) | ❌ 已释放 | ✅ 或超时自动恢复 |
关键结论:
BLOCKED 是 JVM 内部的“被动排队”,WAITING 是程序员主动发起的“协作式挂起”——二者机制完全不同,不可混淆。
? 何时真正需要 notify()?看一个典型生产者-消费者模型
下面是一个精简但完整的 BlockingCounter 示例,清晰展示 wait() 与 notifyAll() 的协作逻辑:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
public class BlockingCounter {
private int value = 0;
private final int max;
public BlockingCounter(int max) {
this.max = max;
}
public synchronized void increment() throws InterruptedException {
while (value >= max) { // 条件不满足 → 主动让出锁并等待
System.out.println(Thread.currentThread().getName() + " waiting (full)");
wait(); // ? 释放锁,进入 WAITING 状态
}
value++;
System.out.println(Thread.currentThread().getName() + " incremented to " + value);
notifyAll(); // ✅ 唤醒所有等待者(可能有多个条件需检查)
}
public synchronized void decrement() throws InterruptedException {
while (value <= 0) {
System.out.println(Thread.currentThread().getName() + " waiting (empty)");
wait();
}
value--;
System.out.println(Thread.currentThread().getName() + " decremented to " + value);
notifyAll();
}
}在这个例子中:
- increment() 在计数达上限时调用 wait(),主动放弃锁,使其他线程(如 decrement())有机会执行;
- decrement() 执行后调用 notifyAll(),通知所有等待线程重新竞争锁并检查条件;
- 若删除 notifyAll(),等待线程将永远卡在 WAITING 状态,程序死锁。
⚠️ 重要注意事项:
- wait()、notify()、notifyAll() 必须在 synchronized 块/方法中调用,否则抛 IllegalMonitorStateException;
- 永远用 while 而非 if 检查等待条件(防止虚假唤醒和条件变更);
- 优先使用 notifyAll() 而非 notify(),除非你 100% 确定只有一个等待者且唤醒顺序无歧义;
- synchronized 方法退出时 不会隐式调用 notify() —— 这是常见误区。它只释放锁,不唤醒 WAITING 线程。
? 总结:一句话记住核心原则
synchronized 负责“谁可以进”,wait/notify 负责“什么时候进”。前者是 JVM 自动保障的基础设施,后者是开发者编排线程协作的高级工具 —— 无协作需求,就无需 notify。

















