AQS的acquireShared通过共享式获取允许多线程并发持锁,核心由子类实现tryAcquireShared决定准入(返回值>0/=0/<0对应不同状态),成功则传播唤醒后继,失败则入队自旋重试,全程依赖state的CAS原子操作保障线程安全。

Java 中 AQS 的 acquireShared 方法通过“共享式获取”机制控制并发,核心在于允许多个线程同时持有锁(如读锁),但需满足特定条件(如资源未被独占、剩余许可数充足等),并借助同步队列与 CAS 状态更新协同完成。
共享锁的准入逻辑:tryAcquireShared 决定是否放行
AQS 本身不定义共享锁语义,而是由子类实现 tryAcquireShared(int arg) 来决定能否获取共享锁:
- 返回值 > 0:表示获取成功,且还有剩余资源可供后续线程获取(例如 ReentrantReadWriteLock.ReadLock 中返回剩余读许可数);
- 返回值 == 0:表示刚好获取成功,无剩余资源;
- 返回值
这个判断是整个共享模式的起点,也是并发控制的第一道闸门。
成功时直接传播:setHeadAndPropagate 确保唤醒后继共享节点
当 tryAcquireShared 返回正数,AQS 不仅设置当前节点为头结点,还会调用 setHeadAndPropagate 尝试唤醒后续可能的共享节点:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 将当前获取成功的节点设为新 head,并清空其 thread 和 prev 引用;
- 检查后继节点是否为共享模式(
node.next != null && node.next.waitStatus == Node.SHARED); - 若满足条件,且 state 仍支持共享(如剩余许可 > 0 或未被独占),则触发
doReleaseShared()唤醒后继; - 该传播机制避免了“唤醒遗漏”,让多个读线程可连续、无锁地进入临界区。
失败时入队阻塞:共享节点排队 + 自旋 + 唤醒接力
若 tryAcquireShared 返回负数,线程会构造一个 Node.SHARED 类型节点加入同步队列尾部,并进入自旋等待:
- 每次自旋前先尝试再次调用
tryAcquireShared(非阻塞重试),避免不必要的挂起; - 若仍失败,且前驱节点是 head,则再试一次(防止刚释放就错过);
- 否则挂起当前线程,等待前驱节点在释放时调用
unparkSuccessor唤醒它; - 被唤醒后继续自旋重试,形成“等待-唤醒-再试”的协作循环。
状态维护与线程安全:state 字段的原子操作是关键
共享锁的并发控制高度依赖 state 字段的含义和 CAS 更新:
- 在
Semaphore中,state 表示剩余许可数,tryAcquireShared比较并尝试 CAS 减少; - 在
CountDownLatch中,state 表示倒计数值,await 本质是共享式获取,直到 state 变为 0; - 所有对 state 的读写都通过
getState()、compareAndSetState()等 volatile + CAS 操作保证可见性与原子性; - 子类必须确保
tryAcquireShared和tryReleaseShared对 state 的解读一致,否则会出现状态错乱。

















