notify仅是轻量级单次唤醒信号,用于使waiting线程转为runnable并参与锁竞争;必须与while条件循环、synchronized块、原子化状态更新配合使用,否则易致通知丢失;复杂场景推荐countdownlatch、blockingqueue等现代api替代。

notify 方法本身不管理“通知流”,它只负责唤醒一个等待中的线程。真正构成任务通知流的是 wait/notify 的配合使用、条件判断逻辑,以及同步结构的设计。
notify 在通知流中承担的角色
它不是调度器,也不是消息总线,而是一个轻量级的“单次唤醒信号”。它的核心作用是打破某个线程在特定对象上的 WAITING 状态,使其重新参与锁竞争——仅此而已。
- 唤醒发生在 notify() 调用之后,但被唤醒线程真正恢复执行,要等当前持有锁的线程退出 synchronized 块释放锁
- 它不传递数据、不指定目标、不保证顺序,只是触发一次状态迁移(WAITING → RUNNABLE)
- 若多个线程在同一个对象上 wait,notify 随机选一个;需要确定性唤醒或避免遗漏,应改用 notifyAll()
构建可靠通知流的关键约束
单纯调用 notify 很容易导致通知丢失或虚假唤醒,必须嵌入规范模式才能形成可信赖的任务流转。
- 必须搭配 while 循环检查条件:不能用 if,否则可能因虚假唤醒或条件未真正满足就继续执行
- 必须在 synchronized 块内调用:确保调用者拥有对象监视器,否则抛 IllegalMonitorStateException
- 通知与条件变更必须原子化:修改共享状态(如 flag = true)和 notify() 必须在同一同步块中完成
- 避免 notify 和 wait 错位对象:wait(obj) 和 notify(obj) 必须作用于同一实例,否则线程永远收不到信号
典型任务通知流场景示例
以“任务准备就绪 → 触发执行”为例,常见于组件初始化、异步回调前置、资源就绪通知等环节:
- 主线程启动子任务后进入 wait,等待子任务完成标记
- 子任务线程更新完成状态(如 done = true),然后调用 notify()
- 主线程被唤醒后,再次检查 done 是否为 true,确认后再继续后续流程
- 若子任务失败或超时,主线程可通过 interrupt 或超时机制退出等待,避免永久阻塞
替代 notify 的现代实践建议
在复杂通知流中,手动维护 wait/notify 容易出错。JDK 提供了更安全、语义更清晰的替代方案:
- 使用 CountDownLatch 实现“一到多”的一次性通知(如启动屏障)
- 用 BlockingQueue 封装生产-消费通知流,自动处理阻塞与唤醒
- 借助 Phaser 或 CyclicBarrier 协调多阶段任务同步
- 对异步结果,优先选用 CompletableFuture,通过 thenAccept / join 等方法自然衔接通知链
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











