notify无法精准唤醒,仅随机唤醒一个wait线程;精准唤醒需靠条件变量+while循环校验、分锁对象(如notempty/notfull)或juc工具类(condition、blockingqueue)实现。

notify 方法本身无法实现精准唤醒,它只唤醒一个等待线程,但不保证是哪一个。Java 的 notify() 是基于对象监视器(monitor)的底层机制,它随机选择一个在该对象上 wait() 的线程唤醒,不支持按条件、优先级或身份指定唤醒目标。所谓“精准唤醒”,必须由开发者通过设计模式和协作逻辑来间接达成,而非依赖 notify() 自身能力。
用条件变量 + while 循环避免虚假唤醒
唤醒后必须重新校验业务条件,因为被唤醒的线程可能不再满足执行前提(例如其他线程已抢先修改状态)。这是实现逻辑精准的关键一步。
- 永远在
while循环中调用wait(),而不是if - 每次从
wait()返回,都重新检查共享状态是否真正就绪 - 示例:生产者-消费者中,消费者需确认队列非空才消费,即使被唤醒也得再判断
为不同条件使用独立锁对象(推荐替代方案)
单个对象上的 wait()/notify() 共享同一等待队列,容易误唤醒。更可控的方式是为不同等待场景分配不同锁对象:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 比如定义
notEmpty和notFull两个Object锁 - 消费者在
notEmpty上wait(),生产者在完成入队后调用notEmpty.notify() - 生产者在
notFull上wait(),消费者出队后调用notFull.notify() - 这样唤醒只影响对应语义的线程,大幅降低干扰
优先考虑 java.util.concurrent 工具类
原生 wait/notify 易出错且难以精准控制。JUC 提供了更安全、语义更明确的替代方案:
-
Condition接口配合ReentrantLock,可为同一锁创建多个条件队列 -
BlockingQueue(如ArrayBlockingQueue)已封装好线程安全的等待/唤醒逻辑 -
Semaphore或CountDownLatch更适合信号量式协调,避免手动管理 wait/notify
慎用 notifyAll,但有时比 notify 更可靠
当多个线程等待同一条件但状态变化影响多个线程时,notify() 可能遗漏应唤醒者。此时 notifyAll() 虽开销略大,却能确保所有相关线程重新竞争并校验条件:
- 例如:一个共享资源变为可用,多个等待线程都可能立即使用
- 若只用
notify(),可能只唤醒一个,其余继续挂起,造成吞吐下降 - 只要条件检查逻辑正确,
notifyAll()不会导致逻辑错误,反而提升健壮性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










