state是aqs中唯一被volatile修饰的核心整型变量,其语义由子类通过tryacquire/tryrelease定义,必须用cas或setstate操作,不可裸赋值;state==0不恒等于无锁,具体含义取决于同步器实现。

state 是 AQS 里唯一被 volatile 修饰的核心整型变量,它不直接等于“锁是否被占用”,而是由具体同步器解释的**状态码**
你看到 ReentrantLock 用它记重入次数、Semaphore 用它记剩余许可数、CountDownLatch 用它记倒数值——说明 state 本身没有固定语义,只是个可原子操作的共享整数。它的意义完全取决于子类怎么实现 tryAcquire 和 tryRelease。
为什么必须用 compareAndSetState 修改 state,不能直接赋值?
因为 state 是多线程竞争的关键字段,直接 state = 1 会丢失更新、破坏原子性。AQS 所有状态变更都基于 CAS(如 compareAndSetState(0, 1))或带自旋的 acquire 流程。哪怕只是“设置为 0”,也得走 setState(0)(内部仍是 volatile 写),而不是裸赋值。
- 错误写法:
state = 0—— 编译不过(state是 private final int,且没提供 public setter) - 危险写法:
setState(1)在没校验前提下直接调用 —— 可能覆盖其他线程刚写入的合法值 - 正确路径:总是通过
tryAcquire/tryRelease回调间接控制,这些方法里再用compareAndSetState或getState+ CAS 循环
state == 0 一定表示无锁?不一定
这是最常被误解的一点。state == 0 只代表当前整数值为 0,不代表同步器处于“空闲”状态。比如:
-
CountDownLatch构造时传3,初始state == 3;减到0才表示放行 —— 此时0是终态,不是空闲态 -
ReentrantLock非公平模式下,一个线程释放锁时设state = 0,但下一刻可能立刻被另一个线程抢到并设为1,中间没有“安全窗口” -
Semaphore(0)初始state == 0,此时所有acquire()都会阻塞 ——0表示“无资源可用”,而非“无人持有”
子类读写 state 的三个硬约束
你自己写 AQS 子类时,绕不开这三条:
立即学习“Java免费学习笔记(深入)”;
- 所有读必须用
getState(),不能直接读字段(字段是private) - 所有写必须用
setState(int)或compareAndSetState(int, int),不能裸赋值 -
tryAcquire和tryRelease必须是无锁逻辑(不能在其中加 synchronized 或调用阻塞方法),否则会死锁 AQS 内部队列机制
真正难的不是看懂 state 是什么,而是想清楚你的同步语义该怎么映射到这个整数上——比如要不要支持超时、是否允许多线程同时 release、state 归零后是否允许再次初始化。这些设计一旦定下来,就很难改。










