notify()本身不保证平稳执行,真正保障的是同步结构与条件判断机制:wait()须在while循环中重检条件,notify()不释放锁且需状态更新后调用,多条件等待应优先用notifyall()。

Java 中 notify() 方法本身不确保被唤醒线程的平稳执行——它只负责从等待队列中随机选一个线程“通知”,后续是否能顺利执行,取决于锁竞争、条件检查和程序逻辑设计。真正保障平稳执行的,是配合使用的同步结构与条件判断机制,而非 notify() 单独完成。
以下几点是实现平稳执行的关键支撑:
notify() 唤醒后必须重新验证业务条件
被 notify() 唤醒的线程不会立刻运行,而是先排队争抢对象锁;即使抢到锁,原等待条件也可能已失效(比如被其他线程抢先修改)。因此:
-
wait()必须写在while循环里,不能用if - 唤醒后必须再次检查条件是否满足,不满足就继续
wait
synchronized (lock) {
while (!shouldProceed()) { // 而非 if (!shouldProceed())
lock.wait();
}
// 此处才安全执行业务逻辑
}
notify() 不释放锁,需等同步块退出后才触发锁竞争
调用 notify() 的线程仍持有锁,被唤醒线程只能进入“入口队列”等待。只有当前线程退出 synchronized 块、释放锁后,被唤醒线程才有机会获取锁。这意味着:
-
notify()后不要立即return或提前结束同步块,否则可能遗漏状态更新 - 关键状态变更(如设置标志位、修改共享变量)必须在
notify()之前完成,并在同一个同步块内
避免信号丢失:唤醒目标要与等待条件严格匹配
notify() 只唤醒一个线程,若多个线程因不同条件等待(例如:有的等“有数据”,有的等“空间空闲”),仅用 notify() 容易唤醒错的线程,导致:
- 唤醒的线程检查条件不满足,再次
wait(),而真正该醒的线程一直挂起 - 潜在死锁或长期饥饿
此时应优先使用 notifyAll(),让所有等待线程都重新评估自身条件。
实际协作中推荐“守门人+双锁”或状态驱动模式
例如经典 ABC 交替打印:
- 每个线程只在自己“轮到”的时候才退出
wait - 使用明确的状态变量(如
state == 0表示该 A 线程执行)配合while循环 -
notify()放在状态更新之后、同步块结束之前,确保唤醒动作与状态变更原子化
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











