CAS机制通过原子比较并更新单个状态变量实现高效状态机转换,如AQS用int state表示锁状态,配合循环乐观重试与队列联动形成闭环控制流,并需防范ABA问题。

CAS 机制在并发框架中实现高效状态机转换,核心在于用原子比较+条件更新替代锁保护的临界区,把“检查→决策→变更”三步压缩成一个不可中断的硬件指令。它不靠阻塞等待,而是靠反复验证状态合法性来推进流程,天然适配状态驱动型逻辑。
状态变量必须是单个可原子操作的值
高效转换的前提是状态本身能被 CAS 直接操作。比如 AQS 中用 int state 表示锁状态:0 表示未锁定,1 表示已锁定,>1 表示重入次数。这个整型变量就是状态机的“唯一权威视图”。所有状态跃迁(如 acquire → tryAcquire → setState)都围绕它展开,避免多字段耦合导致 CAS 失效。
- 不能把“是否加锁”和“持有线程ID”拆成两个独立 volatile 变量去分别更新——那样无法保证二者一致性
- 若需扩展状态信息(如带版本、时间戳或标记位),可用复合结构:AtomicInteger 存储 packed int,或 AtomicStampedReference 带版本号
- ConcurrentHashMap 的 Node.hash 字段也承担类似角色:负值表示正在扩容或树化,CAS 修改 hash 即触发对应状态流转
状态跃迁逻辑封装在循环 CAS 中
真实的状态转换不是一次写入完成的,而是在 while 循环里不断读取当前值、判断是否满足跃迁条件、尝试 CAS 更新——成功则退出,失败则重试。这叫“乐观重试模式”,本质是把同步成本从“等锁”转为“重算”。
- 例如 ReentrantLock.tryAcquire():先 CAS 尝试将 state 从 0 设为 1;失败说明已被占用,再检查是否可重入(state>0 且 owner 是当前线程)
- CountDownLatch.await() 内部其实也在循环 CAS 修改 state,直到变为 0 才唤醒所有等待线程
- 关键点是每次循环前重新读取最新 state,确保依据的是实时状态,而非缓存旧值
结合队列与状态联动形成闭环控制流
纯 CAS 只解决“改一个数”的问题,真正高效的状态机需要配合等待队列(如 AQS 的 CLH 队列)实现阻塞/唤醒协同。CAS 更新状态只是起点,后续动作由状态值驱动:
- 当 CAS 成功将 state 设为 1,表示获取锁成功,直接返回
- 当 CAS 失败且 state != 0,说明锁被占,此时将当前线程封装为 Node 加入同步队列,并自旋检查前驱节点是否为 head —— 这个检查本身又依赖对 queue.head 和 node.prev 的 CAS 或 volatile 读
- 释放锁时 CAS 将 state 减到 0,再 unpark 队列首节点;被唤醒的线程再次 CAS 尝试获取,形成“状态变更 → 触发动作 → 新状态校验”的闭环
避免 ABA 导致的状态误判
状态机最怕“看似没变,实则已轮转”。比如 state 从 1→0→1,CAS 会认为没变而允许更新,但中间可能已完成一次完整生命周期(如信号量 release/acquire)。这时仅靠值比较会跳过必要校验。
- 简单场景可用 AtomicStampedReference,在 state 上叠加版本号,每次变更 stamp +1
- 更复杂状态(如任务执行阶段:INIT → RUNNING → DONE → CLEANUP)建议用枚举+AtomicIntegerFieldUpdater,配合 if-else 显式校验合法转移路径
- Netty 的 ChannelHandler 状态管理就采用类似思路:用 volatile int + 明确的 transition 方法,禁止非法跳转


















