AQS 中 state 的线程安全性由 volatile 修饰与 CAS 原子操作协同保障:volatile 确保可见性与有序性,CAS 保证修改原子性,二者缺一不可;不同同步器依 state 语义定制 CAS 使用逻辑。

AQS 中的 state 是一个核心同步状态变量,它的线程安全性不是靠锁保障的,而是靠 volatile 修饰 + CAS 原子操作 协同实现的。两者缺一不可:volatile 解决“看到什么”,CAS 解决“改成什么”。
volatile 保证 state 的可见性与有序性
state 被声明为 private volatile int state,这带来两个关键保障:
- 可见性:任意线程对 state 的写操作,会立即刷新到主内存;其他线程读取时,必须从主内存重新加载,不会因 CPU 缓存导致读到过期值(比如释放锁后 state=0,但等待线程仍读到旧的 state=1)。
- 禁止重排序:JVM 和 CPU 不会把对 state 的读写与其他指令乱序执行。例如,加锁成功后初始化资源的操作,不会被提前到 CAS 修改 state 之前执行。
CAS 确保 state 修改的原子性
AQS 所有对 state 的关键变更(如获取锁、释放锁、计数更新)都使用 compareAndSetState(expect, update),底层调用 Unsafe 的原子指令:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 它先读取当前 state 值,只有当该值等于预期值
expect时,才原子地将其设为update;否则失败并返回 false。 - 这种“检查-更新”逻辑天然适合锁竞争场景:比如 ReentrantLock 尝试加锁,就执行
CAS(state, 0, 1);成功即获锁,失败则说明已被占用,走排队逻辑。 - CAS 是乐观策略,不阻塞线程,避免了 synchronized 带来的上下文切换开销。
volatile 与 CAS 如何协同工作
单独用 volatile 无法保证复合操作的原子性(如“读 state → 判断 → 写新值”可能被中断);单独用 CAS 又依赖每次读取的是最新值——这就需要 volatile 来兜底:
立即学习“Java免费学习笔记(深入)”;
- CAS 的“读取当前值”动作,依靠 volatile 语义确保读到的是主内存中的最新 state,而不是线程本地缓存的脏值。
- CAS 成功后的“写入新值”,也借助 volatile 的写屏障,让新值对所有线程立即可见。
- 像
getState()、setState()这类非条件赋值方法,虽不涉及 CAS,但因 state 是 volatile 的,其读写本身也具备 happens-before 关系,能安全用于状态快照或初始化等场景。
不同同步器中 state 的含义决定 CAS 使用方式
state 的语义由具体子类定义,CAS 的使用逻辑随之变化:
-
ReentrantLock:state=0 表示无锁,state=1 表示已占有,>1 表示重入次数。加锁用
CAS(0,1),重入用setState(state+1)(此时无需 CAS,因已持锁)。 -
Semaphore:state 表示剩余许可数。acquire() 尝试
CAS(n, n−1),release() 直接setState(state+1)。 -
CountDownLatch:state 表示倒计数值。countDown() 执行
CAS(n, n−1),直到变为 0 才唤醒等待线程。

















