java中wait()、notify()、notifyall()必须在synchronized块中调用,用于线程协作;需用while循环检查条件防虚假唤醒;应使用private final专用锁对象而非字符串常量。

Java 中 Object 类提供的线程等待方法(wait()、notify()、notifyAll())必须在同步上下文中使用,否则会抛出 IllegalMonitorStateException。它们不是简单的“暂停线程”,而是用于线程间协作的通信机制,核心在于“条件等待 + 唤醒通知”的配合。
必须在 synchronized 块或方法中调用
这三个方法操作的是对象的内置监视器(monitor),只有当前线程持有该对象的锁时才能调用。直接调用会立即失败。
-
wait():释放当前持有的锁,并使线程进入 WAITING 状态,直到被唤醒或中断 -
notify():随机唤醒一个正在此对象上等待的线程(不保证唤醒顺序) -
notifyAll():唤醒所有在此对象上等待的线程(更安全,推荐优先使用)
等待必须配合 while 循环检查条件
不能用 if 判断后直接 wait(),因为存在虚假唤醒(spurious wakeup)和条件变更竞争问题。正确做法是用 while 循环重检业务条件是否真正满足。
例如实现一个简单的阻塞队列节点:
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // 条件不满足才等待
}
return queue.remove();
}
notify/notifyAll 应在修改共享状态后立即调用
唤醒操作本身不保证条件已满足,它只是“提示可能有变化”。因此必须先更新共享变量(如设置标志位、添加元素),再调用 notify() 或 notifyAll(),且同样需在同步块内完成。
- 错误:先
notify()再改状态 → 等待线程醒来发现条件仍不成立,又得继续等 - 正确:改状态 →
notifyAll()→ 退出同步块
避免在 String、Integer 等常量池对象上调用 wait/notify
这些对象可能被多个地方共享,容易引发意外唤醒或死锁。应使用专用的、私有的锁对象:
private final Object lock = new Object(); // 推荐 // 而非 private final String lock = "myLock"; // 危险:字符串常量池共享
锁对象应是 private final,不对外暴露,防止外部误同步干扰内部逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











