Condition的等待队列是AQS中基于Node动态构建的单向逻辑链表,每个Condition实例独享一个队列,await时新建Node加入队尾,signal时仅调整指针移动节点,内存按需分配且轻量。

Condition 的等待队列不是靠“分配内存”来管理的,而是基于 AQS(AbstractQueuedSynchronizer)内部的节点结构动态组织的链表,本质是逻辑队列,不主动申请堆内存块。
等待队列是 AQS 中的条件队列(Condition Queue)
每个 Condition 实例背后都维护一个独立的单向链表,节点类型是 AQS 的 Node,通过 nextWaiter 字段链接。这个队列与同步队列(Sync Queue)分离,互不影响。
- 调用 await() 时,当前线程会从同步队列中移出,封装为 Node 加入该 Condition 对应的条件队列尾部
- 节点创建发生在 await 执行过程中,由 JVM 在栈帧或堆上构造 Node 对象(通常在堆),但这是 AQS 内部自动完成的,开发者无需干预
- 没有预分配、不扩容、不复用节点——每次 await 都新建 Node;每次 signal 后被唤醒的 Node 会被移出条件队列,加入同步队列等待争锁
内存开销小且按需发生
Node 对象本身很轻量(几个引用 + int 状态字段),一次 await 只新增一个节点;大量线程等待也不会提前占内存,只在真正阻塞时才实例化。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 不会因为声明了 Condition 就占用内存——没线程 await,就没有节点
- signal() 或 signalAll() 不会复制或移动节点数据,只是调整指针(如将头节点从条件队列摘下,插入同步队列)
- 被唤醒线程成功获取锁后,对应 Node 会被 GC 回收(若无外部引用)
多个 Condition 对应多个独立队列
同一个 ReentrantLock 可调用多次 newCondition(),每次返回新 Condition 实例,各自拥有专属条件队列。
立即学习“Java免费学习笔记(深入)”;
- 比如生产者用 notFull,消费者用 notEmpty——两个队列物理隔离,避免 notify 误唤醒
- 各队列生命周期独立:一个 Condition 的 await 线程不会影响另一个 Condition 的等待状态
- 这种设计让内存和逻辑都更可控,比 Object 的单一 wait set 更精准
不需要手动管理,但要注意泄漏风险
虽然底层自动管理,但若 await 后永远不 signal,节点会长期驻留堆中,形成“等待线程泄漏”。
- 尤其在超时未设置、条件判断有缺陷(如 while 循环条件写错)时,线程卡在 await 不退出
- 对应的 Node 和线程对象无法被回收,可能引发 OOM(尤其高并发长期运行服务)
- 推荐始终配合超时方法(如 await(5, TimeUnit.SECONDS))或严格校验唤醒逻辑

















