Node节点的waitstatus
大约 3 分钟
这段注释非常重要,它定义了 AQS 节点(Node)的核心状态机 waitStatus。这个字段决定了线程是应该阻塞、被唤醒、还是被忽略。
waitStatus 是一个 int 类型的整数,主要包含以下 4 种特定的状态值(以及默认值 0):
1. SIGNAL (-1): "后继者需要被叫醒"
- 含义:当前节点的后继节点(Successor)已经(或即将)被阻塞(park),所以当前节点在释放锁(release)或取消(cancel)时,必须负责唤醒(unpark)它的后继节点。
- 作用:这是最常见的状态。当一个线程 B 发现自己抢不到锁,准备去睡大觉之前,它必须先把它前面的线程 A 的状态改为
SIGNAL。意思就是贴个条子:“A 兄弟,我睡了,你走的时候记得叫醒我。”
2. CANCELLED (1): "已取消"
- 含义:该节点因为超时(Timeout)或被中断(Interrupt)而被取消了。
- 特征:
- 这是一个终结状态。节点一旦变成
CANCELLED,就永远不会再变成其他状态。 - 处于此状态的线程永远不会再次阻塞。
- 在队列遍历时,遇到
CANCELLED的节点通常会直接跳过(unlink),把它踢出队列。
- 这是一个终结状态。节点一旦变成
3. CONDITION (-2): "在条件队列中"
- 含义:该节点目前位于 Condition 队列(等待队列)中,而不是在 CLH 同步队列(竞争队列)中。
- 流转:
- 当节点在 Condition 队列时,状态是
-2。 - 当它被
signal()唤醒并转移到 CLH 队列时,状态会被修改为0。
- 当节点在 Condition 队列时,状态是
- 注意:这个值仅仅是为了标记节点在哪里,简化逻辑。
4. PROPAGATE (-3): "共享模式下的传播"
- 含义:用于 共享模式(Shared Mode,如 CountDownLatch, Semaphore)。
- 作用:表示
releaseShared操作需要传播给后续节点。 - 细节:这个状态只会在 head(头节点) 上设置。它的目的是为了解决某些并发场景下,信号量释放信号可能被“吞掉”的 bug,确保唤醒动作能像多米诺骨牌一样传递下去。
5. 0 (默认值): "无特殊状态"
- 含义:以上都不是。
- 场景:
- 新建节点:当一个节点刚被初始化进入 CLH 队列时,默认是 0。
- 队尾节点:队列目前的最后一个节点通常是 0(因为它后面还没人求它唤醒)。
关键设计哲学(注释最后一段)
"The values are arranged numerically to simplify use. Non-negative values mean that a node doesn't need to signal."
- 数值安排的玄机:
- 负数 (< 0):代表节点处于有效等待状态(SIGNAL, CONDITION, PROPAGATE),需要被关注或处理。
- 非负数 (>= 0):代表节点不需要去唤醒别人(0: 还没人排在它后面)或者它自己已经废了(1: CANCELLED)。
- 代码简化:源码中经常直接判断
ws > 0来快速识别节点是否已取消,或者ws < 0来判断是否需要执行特定逻辑,而不需要一个个比对枚举值。
总结表
| 状态值 | 英文名 | 含义 | 谁在用 |
|---|---|---|---|
| 1 | CANCELLED | 已取消(超时/中断),应当被踢出队列 | 独占/共享/Condition |
| -1 | SIGNAL | 后面有人睡着了,释放时必须叫醒它 | 独占/共享 |
| -2 | CONDITION | 在等待室(Condition队列)里休息 | Condition |
| -3 | PROPAGATE | 传播唤醒,通知更多人醒来 | 共享模式 |
| 0 | INITIAL | 初始状态,还没发生什么特殊事 | 所有 |