AQS 的 state 是 volatile int,其语义由子类定义:独占锁用 whole state 表示重入次数,共享锁用 state 表示许可数,读写锁高低 16 位分别存读/写计数;所有修改必须 CAS,禁止直接赋值,需避免状态歧义。

AQS 的 state 变量本质是一个 volatile int,它本身不带语义,设计锁状态的关键在于**你如何解释和操作它**。不是 state 怎么“设计”,而是你如何用它编码锁的业务含义。
用单一整数编码多种锁状态
state 是一个 32 位整数,可拆解使用:
-
独占锁(如 ReentrantLock):直接用整个 state 表示重入次数。0 表示未锁定,1 表示首次获取,2 表示重入一次……每次
acquire前 CAS 自增,release时自减,减到 0 才真正释放。 -
共享锁(如 Semaphore、CountDownLatch):state 表示剩余许可数或待完成数量。acquire 先 CAS 减去所需数量(如
compareAndSet(state, state - permits)),失败则排队;release 则 CAS 增加。 -
读写锁(如 ReentrantReadWriteLock):高位 16 位存读锁计数,低位 16 位存写锁重入数。用位运算隔离读/写状态:
int r = state >>> 16;
int w = state & 0xFFFF;
必须配合 CAS 和 volatile 语义使用
state 本身是 volatile,但仅靠 volatile 不足以保证原子更新(如 i++ 非原子)。所有修改必须基于 Unsafe.compareAndSwapInt 或 AQS 提供的 compareAndSetState(expect, update):
- 获取锁时,先读当前 state,再 CAS 尝试变更(如从 0→1 或 1→2);失败说明状态已变,需重试或入队。
- 释放锁时,同样 CAS 更新(如从 2→1 或 1→0),只有 state 变为 0 才唤醒后继节点。
- 禁止直接赋值
state = xxx—— 会破坏同步契约,导致可见性或原子性问题。
避免状态歧义,定义清晰的取值约定
state 的每个取值必须有唯一、无歧义的锁语义:
- 不要让 state == 0 同时表示“未加锁”和“共享资源耗尽”——语义冲突会导致逻辑混乱。
- 如果需要表达“锁被某线程持有 + 等待队列长度 + 条件队列数”,建议拆成多个字段(如 ReentrantLock 内部额外维护 ownerThread、waiters 等),state 专注核心所有权/计数。
- 调试时可通过
getState()检查 state 值,结合你的约定快速定位锁状态(例如 state=5 在读写锁中意味着 5 把读锁被持有)。
可扩展:state 只是起点,复杂逻辑靠子类协同
AQS 不强制 state 必须代表锁,它只是一个同步器的状态载体。实际锁行为由子类实现决定:
-
tryAcquire(int arg):你定义“什么情况下算获取成功”——arg 通常传入重入次数或许可数,内部用 state 判断并更新。 -
tryRelease(int arg):你定义“释放是否彻底”——比如只减 state,但只有 state==0 才返回 true 触发唤醒。 - 公平性、中断响应、超时等,都不依赖 state 结构,而靠 AQS 框架+子类对 state 的解读与协作。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











