condition 替代 wait/notify 是重构协作逻辑:依托 aqs 双队列解耦多条件、消除盲唤醒、支持中断与超时;需在 lock 保护下使用,遵循 while 循环重检条件,并善用带超时/中断的 await 方法提升韧性。

直接用 Condition 替代 wait/notify 不是简单替换 API,而是重构协作逻辑的底层结构。核心在于利用 AQS 的双队列机制解耦等待条件、消除盲唤醒、支持中断与超时——这对高并发、低延迟场景(如自定义阻塞队列、流控组件、实时任务调度)尤为关键。
拆分多条件,避免 notifyAll 引发的“唤醒风暴”
传统 synchronized + wait/notify 只能绑定一个对象锁,所有线程挤在同一个等待队列里。生产者调用 notify(),可能唤醒另一个生产者;消费者 notify(),也可能唤醒其他消费者。线程被唤醒后还要重新抢锁、再检查条件,白白消耗 CPU。
Condition 允许一个 Lock 关联多个独立条件队列:
- 为“队列非空”单独建一个 notEmpty 条件,消费者只 await 这个
- 为“队列未满”单独建一个 notFull 条件,生产者只 await 这个
- 生产者完成入队后,只 signal(notEmpty),精准唤醒等待消费的线程
- 消费者完成出队后,只 signal(notFull),精准唤醒等待生产的线程
这样,每次唤醒都命中目标角色,无冗余竞争,吞吐量和响应延迟显著改善。
确保 await/signal 始终在 lock 保护下执行
Condition 不是独立工作的,它必须依附于 Lock,且所有操作必须在持有锁的前提下进行。这不是约束,而是安全前提:
- await() 前必须 lock.lock():保证判断条件(如 size == 0)和进入等待是原子的,防止条件判断后被其他线程修改
- await() 内部会自动释放锁,并把当前线程节点从同步队列移到条件队列,真正挂起前已让出锁资源
- signal() 也必须在 lock 持有状态下调用:确保唤醒动作与状态变更(如 size++)构成临界区,避免信号丢失
漏掉 lock 或顺序错乱(比如先 await 后 lock),会抛 IllegalMonitorStateException,这是设计上的强校验。
用带超时或可中断的等待方法提升系统韧性
wait() 不响应中断,无法设置超时,一旦被错误唤醒或条件长期不满足,线程就卡死。Condition 提供了更健壮的选择:
- awaitNanos(long):指定纳秒级超时,返回剩余等待时间,可用于实现带退避的重试逻辑
- awaitUntil(Date):按绝对时间点等待,适合定时类任务(如延迟消息投递)
- await() 抛 InterruptedException:上层可捕获并清理资源、记录日志、触发熔断,不会让线程静默失效
在服务治理、限流降级等场景中,这些能力直接决定系统能否优雅失败、快速恢复。
理解节点流转,避免误判唤醒来源
一个线程调用 await(),它的 Node 会从 AQS 同步队列移出,加入 Condition 的单向等待队列;被 signal() 后,Node 被移回同步队列尾部,等待再次竞争锁。这个过程不是“立刻执行”,而是“排队重试”。
这意味着:
- signal() 不等于“马上运行”,只是让它有机会重新抢锁
- await() 返回时,不代表条件一定成立,仍需在 while 循环中重新检查(即所谓的“虚假唤醒”防护)
- 若被中断唤醒,await() 会抛异常,但节点可能已移回同步队列,需注意锁清理逻辑
写法上坚持“if → while + await”模式,而不是“if → await”,是避免逻辑错乱的基本防线。











