aqs通过node的waitstatus字段控制节点行为,而非“nodename”;cancelled(1)表示线程取消,signal(-1)表示后继需唤醒,condition(-2)表示在条件队列中等待,propagate(-3)用于共享模式下唤醒传播。

AQS(AbstractQueuedSynchronizer)并不通过“nodename”控制节点行为——它根本没有“nodename”这个概念。你提到的 CANCELLED、SIGNAL、CONDITION、PROPAGATE 是 Node 类中定义的 waitStatus 状态位,用于标记队列中节点(Node 实例)的当前语义状态,从而决定其在同步等待、唤醒、取消等流程中的行为。
waitStatus 是节点的“行为开关”,不是名字
Node 类里没有字段叫 nodename;每个 Node 是一个内部对象,靠 waitStatus 字段(int 类型)表达其生命周期阶段和协作意图:
- CANCELLED(1):该节点代表的线程已取消获取同步状态(如超时、中断)。AQS 会跳过它,在出队或唤醒遍历时主动剔除。
- SIGNAL(-1):当前节点的后继节点需要被唤醒(即“我释放锁后,请唤醒我后面那个”)。这是独占模式下最常见且关键的状态,前置节点在释放资源前必须确保后继处于 SIGNAL 才能安全 unpark。
- CONDITION(-2):该节点位于条件队列(ConditionObject 的 wait queue)中,尚未转移到同步队列。此时它不参与 AQS 主同步队列的调度,只有 signal() 被调用时才转为同步队列节点,并重置 waitStatus 为 0。
- PROPAGATE(-3):仅用于共享模式(如 CountDownLatch、Semaphore),表示本次 releaseShared 应继续传播唤醒后续共享节点(避免唤醒丢失)。常出现在 doReleaseShared 中的 CAS 更新逻辑里。
状态如何影响具体行为?看三个典型场景
waitStatus 不是静态标签,而是驱动 AQS 内部算法分支的核心依据:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 入队时默认设为 0:新节点加入同步队列(acquireQueued)初始 waitStatus=0,表示“等待中,无特殊意图”。
- 前置节点释放时检查 SIGNAL:当 tryRelease 成功,AQS 调用 unparkSuccessor,只唤醒 waitStatus ≤ 0 的第一个后继;若后继是 CANCELLED,则跳过,直到找到可唤醒节点。
- await() 时设为 CONDITION:调用 Condition.await() 会把当前线程包装为 Node 加入条件队列,并设置 waitStatus = CONDITION;signal() 则将其移入同步队列,同时设 waitStatus = 0(准备参与竞争)。
状态变更不是随意写的,全靠 CAS 安全更新
AQS 所有对 waitStatus 的修改都使用 compareAndSetWaitStatus(基于 Unsafe CAS),确保多线程环境下状态变更原子、可见:
- 设置 SIGNAL:enq() 入队后、acquireQueued 中失败重试前,会尝试将前驱节点设为 SIGNAL(保障自己能被唤醒)。
- 设置 CANCELLED:acquireInterruptibly 或 tryAcquireNanos 检测到中断/超时时,调用 cancelAcquire,将节点 waitStatus 设为 CANCELLED,并清理前后指针。
- 设置 PROPAGATE:doReleaseShared 中,若发现 head 状态为 0,会 CAS 改为 PROPAGATE,再重试唤醒,防止共享释放漏通知。
别混淆:CONDITION 和同步队列无关
CONDITION 状态的节点 永远不会出现在同步队列(sync queue)中,它只属于 Condition 的单独等待队列。一旦 signal,节点被转移到 sync queue,waitStatus 就被清为 0 —— 此时它才开始参与 lock/unlock 的标准流程。混用这两个队列或误读状态含义,是理解 AQS 时最常见的误区之一。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










