notifyall本身不保证安全唤醒,需配合while循环检查条件、在同步块内先更新状态再调用、且必须持有锁;它使等待线程转为blocked并竞争锁,并非并发执行。

notifyAll 本身不保证“安全唤醒”,它只是通知所有在当前对象监视器上等待的线程去竞争锁;真正的安全取决于你如何设计等待条件和同步逻辑。
必须配合 while 循环检查等待条件
用 if 判断条件后调用 wait() 是危险的——虚假唤醒或过早唤醒会导致线程跳过条件检查,直接执行后续逻辑,引发数据不一致。正确做法是用 while 循环包裹 wait():
- 每次从
wait()返回时都重新检查条件是否真正满足 - 不满足就继续等待,避免误执行
- 例如:生产者-消费者中,消费者必须循环检查“队列非空”,不能只判断一次
唤醒前确保共享状态已正确更新
notifyAll() 应该在修改完共享变量、使等待条件可能变为 true 之后调用,并且必须在同一个同步块内完成:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先更新状态(如设置标志位、添加元素、修改计数器)
- 再调用
notifyAll() - 两者都在
synchronized块中,防止状态更新与唤醒操作被其他线程穿插 - 否则可能出现:状态还没改好,线程就被唤醒并检查失败,又回去等待
避免在不持有锁的情况下调用 notifyAll
notifyAll() 必须在同步上下文中调用(即当前线程已获得该对象的 monitor 锁),否则抛出 IllegalMonitorStateException:
- 只能在
synchronized(obj) { ... obj.notifyAll(); ... }中调用 - 不能在
ReentrantLock+Condition场景下误用notifyAll()(应使用condition.signalAll()) - 混淆内置锁和显式锁会导致运行时异常或逻辑失效
注意 notifyAll 不等于“全部立即执行”
调用 notifyAll() 后,所有等待线程会从 WAITING 状态变为 BLOCKED,排队争抢对象锁:
- 只有一个线程能先拿到锁并继续执行
- 其余线程仍需等待,直到前一个线程释放锁并退出同步块
- 所以不是并发执行,而是“依次唤醒+逐个竞争”,实际执行顺序不确定
- 若业务需要严格顺序或限制并发数,需额外加控制(如信号量、计数器)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










