Condition 依托 AQS 双队列实现精准唤醒:一锁多条件队列隔离、await 原子释放入队、signal 定向迁移头节点至同步队列、唤醒后需重抢锁并二次校验条件。

Condition 配合 AQS 实现精准唤醒,核心在于“一锁多队列 + 状态分离 + 原子流转”。它不是简单替代 wait/notify,而是依托 AQS 的双队列结构(同步队列 + 条件队列),让不同业务条件拥有各自独立的等待链表,唤醒时只触达目标队列中的线程。
每个 Condition 对应一个独立的条件队列
AQS 允许一个 Lock(如 ReentrantLock)创建多个 Condition 实例,例如:
- notEmpty:专供消费者等待“队列非空”
- notFull:专供生产者等待“队列未满”
它们各自维护自己的单向链表(firstWaiter → lastWaiter),节点是封装了线程的 Node,waitStatus 初始为 CONDITION。这些队列彼此隔离,互不干扰 —— 消费者 await(notEmpty) 不会影响生产者在 notFull 队列里的排队状态。
await() 触发原子状态切换:释放锁 + 入条件队列 + 阻塞
调用 await() 时,并非直接 park,而是一组不可拆分的操作:
立即学习“Java免费学习笔记(深入)”;
- 检查中断状态,已中断则立即抛 InterruptedException
- 将当前线程构造成 Node,追加到该 Condition 的条件队列尾部
- 调用 fullyRelease() 完全释放锁(支持重入,会一次性释放全部 state 计数)
- 调用 LockSupport.park() 挂起线程
此时线程既不在同步队列中竞争锁,也不持有锁,真正“干净退出”临界区。
signal() 只唤醒对应条件队列的头节点
当某个条件满足(如 put 后队列非空),调用 notEmpty.signal():
- 从 notEmpty 的条件队列中取出头节点
- 将其 waitStatus 改为 0,并转移到 AQS 的同步队列尾部(作为普通等待锁的节点)
- 若该节点前驱是 head 或能被设为 SIGNAL,则触发 unpark 后继线程
这个过程不会碰 notFull 队列里的任何节点,也不会唤醒正在等“未满”的生产者 —— 唤醒完全定向,没有无效竞争。
被唤醒线程重新争锁并校验条件
线程被 unpark 后,需重新获取锁(可能在同步队列中排队),获得锁后才从 await() 返回。此时必须再次检查业务条件(如 while(buffer.isEmpty())),因为:
- 可能被虚假唤醒(signal() 调用后又被其他线程抢先消费)
- 可能因中断被唤醒,需处理中断标志
这种“唤醒→抢锁→再判断”的闭环设计,保证了语义安全与响应精度。


















