Java中 Object 类 notify 方法如何唤醒单个等待线程

作者:袖梨 2026-07-21
notify() 不保证唤醒指定线程,仅随机唤醒等待队列中一个线程,被唤醒者需重新竞争锁;无法指定目标是因监视器机制不记录线程身份且无相关API;精准唤醒应改用Condition、标志位+notifyAll或阻塞队列等替代方案。

Java 中 Object 类的 notify() 方法**并不保证唤醒“单个指定”线程**,它只是从当前对象监视器(monitor)的等待队列中**随机唤醒一个正在 wait() 的线程**——这个“单个”是存在性意义上的(唤醒一个,而非全部),但不是可控、可选择的“某一个”。

notify() 的唤醒行为本质

notify() 的设计目标是打破等待状态,避免虚假唤醒或资源竞争,但它不提供线程选择能力:

  • JVM 从该对象的等待队列(Entry Set 或 Wait Set,取决于 JVM 实现)中选取一个处于 WAITING 状态的线程,具体选哪个由 JVM 决定,不可预测;
  • 被唤醒的线程不会立即执行,而是重新竞争该对象的监视器锁,只有抢到锁后才能继续执行;
  • 如果等待队列为空,notify() 不做任何事,无异常也无提示。

为什么不能指定唤醒某个线程

这是 Java 内存模型和监视器机制的设计限制:

  • wait()/notify() 基于对象级别的监视器,不记录线程身份或优先级;
  • 没有 API 接口支持传入线程引用或条件标识;
  • 强行绑定线程与唤醒逻辑容易引发死锁或竞态,违背 monitor 的简洁抽象原则。

想精准唤醒特定线程?用替代方案

若业务需要“唤醒某个特定等待者”,应放弃 notify(),改用更可控的协作机制:

立即学习“Java免费学习笔记(深入)”;

  • 使用 java.util.concurrent 工具类:如 Condition 配合 ReentrantLock,可为不同等待条件创建多个 Condition 实例,实现分组唤醒;
  • 用标志位 + notifyAll() + 循环检查:每个等待线程按自身关心的条件等待,唤醒后重新判断是否轮到自己处理,未命中则继续 wait()
  • 使用阻塞队列(如 LinkedBlockingQueue)或信号量(Semaphore:将“唤醒请求”建模为数据或许可,让目标线程主动消费。

典型误用提醒

以下写法看似“唤醒单个”,实则不可靠:

❌ 错误示例:
synchronized (obj) {    obj.notify(); // 无法确保唤醒的是你期望的那个线程}

即使只有一条线程在等,也不建议依赖此行为做逻辑分支——因为多线程环境下,可能有新线程在 notify() 后、被唤醒前进入 wait(),导致唤醒错乱。

相关文章

精彩推荐