notify仅触发唤醒,不管理等待池;必须在synchronized块内调用,配合while循环条件检查、慎用notifyAll,并建议加超时wait以防永久阻塞。

notify 方法本身并不“管理”等待池,它只是触发一次唤醒动作。真正高效管理线程等待池,靠的是**正确的调用时机、配合条件变量的循环检查,以及与 notifyAll 的合理取舍**。单纯依赖 notify 容易引发线程饥饿或逻辑卡死,这不是方法能力不足,而是使用方式的问题。
必须在同步块中调用,且持有锁
notify 只能在当前线程已获得目标对象监视器锁的前提下调用。否则会立即抛出 IllegalMonitorStateException。这意味着:
- 调用 notify 前,必须用 synchronized(obj) 包裹相关逻辑
- 通常在修改完共享状态(如队列非空、资源就绪)后立即 notify,确保唤醒时条件已真实满足
- notify 不会释放锁,它只发信号;锁要等到 synchronized 块结束才释放,此时被唤醒线程才能竞争
永远配合 while 循环检查条件
不能写成 if (condition) { wait(); },必须是:
synchronized(lock) {
while (!conditionMet) {
lock.wait();
}
// 执行业务逻辑
}
原因在于:
立即学习“Java免费学习笔记(深入)”;
- 存在虚假唤醒(spurious wakeup):JVM 可能在无 notify 时唤醒线程
- 多个线程可能等待同一条件,但只有部分满足后续执行前提(如生产者唤醒消费者,但缓冲区仍为空)
- 仅靠一次判断无法保证唤醒后条件依然成立
慎用 notify,优先考虑 notifyAll
notify 随机唤醒一个等待线程,看似轻量,但在多数实际场景中风险更高:
- 若被唤醒的是“不合适”的线程(比如消费者被唤醒时缓冲区仍空),它会再次 wait,而其他本该执行的线程继续沉睡
- 在多条件共存场景(如同时有读/写等待、空/满等待),notify 容易遗漏关键线程,导致死锁或响应延迟
- notifyAll 虽带来额外竞争开销,但能确保所有等待方重新评估自身条件,系统行为更可预测、更健壮
仅当明确知道:只有一个线程能推进状态,且唤醒任意一个都等价(例如互斥资源的单一可用者),才可安全使用 notify。
结合超时 wait 避免永久阻塞
即使使用 notify,也不能完全排除唤醒丢失或逻辑异常。建议对 wait 加上合理超时:
- 使用 wait(timeout) 替代无参 wait,防止因 notify 遗漏或条件更新失败导致线程无限挂起
- 超时后仍需在循环中重检条件,而非直接执行——超时不是成功信号,只是兜底机制
- 典型值如 100–5000 毫秒,取决于业务响应要求和系统负载


















