doAcquireSharedInterruptibly 是 AQS 共享模式下可中断获取的核心闭环方法,以“尝试→失败→入队→挂起→唤醒→重试”确保响应中断且不丢失状态;起点为子类实现的 tryAcquireShared,返回≥0表示成功并直接退出。

doAcquireSharedInterruptibly 是 AQS 中处理共享模式下可中断获取的核心闭环方法,它不直接“高频抢占”state,而是通过“尝试→失败→入队→挂起→唤醒→重试”的原子闭环,确保线程在竞争中既响应中断,又不丢失状态变更。关键不在“抢”,而在“等得明白、醒得及时、试得安全”。
共享获取的闭环起点:tryAcquireShared 的语义约定
该方法由子类实现,返回值决定后续流程走向:
- 返回 ≥0:表示获取成功(如 Semaphore 剩余许可数 > 0,或 CountDownLatch 计数未归零),直接退出,不入队
- 返回
- 注意:返回值不是布尔值,而是“剩余可用量”或“是否满足条件”的量化表达,这为后续传播唤醒(propagate)提供依据
入队与挂起:addWaiter + acquireQueued 的协同
当 tryAcquireShared 失败后,线程被封装为 SHARED 类型 Node,插入同步队列尾部:
- addWaiter(Node.SHARED) 使用 CAS 尾插,失败则回退到 enq 自旋入队,保证节点一定落位
- acquireQueued 中,线程不会立即 park;会先检查前驱是否为 head,且再次调用 tryAcquireShared —— 这是“唤醒即重试”的关键,避免虚假唤醒后盲目挂起
- 仅当确认前驱是 head 且再次 tryAcquireShared 仍失败时,才调用 shouldParkAfterFailedAcquire 设置前驱 waitStatus = SIGNAL,并最终 park
中断响应:selfInterrupt 与检查时机的精确控制
中断不打断挂起过程,而是在两个安全点介入:
- park 返回后(被唤醒或被中断),检查 Thread.interrupted() —— 若为 true,则抛出 InterruptedException 并清理节点(cancelAcquire)
- 在 acquireQueued 循环内每次 park 前,也会检查中断状态;若已中断,则不再 park,直接走取消逻辑
- 这种设计避免了 park 期间中断被忽略,也防止了未 park 就抛异常导致队列结构损坏
状态更新与唤醒传播:releaseShared 的反向驱动
共享模式的闭环完整性依赖释放端的正确传播:
- 当某线程调用 releaseShared(如 Semaphore.release 或 CountDownLatch.countDown),会触发 doReleaseShared
- doReleaseShared 遍历同步队列,对每个 waitStatus == SIGNAL 的 SHARED 节点调用 unparkSuccessor,并尝试将 head 后继设为新 head
- 更重要的是:它会在 unpark 后继续循环,检查是否还有后续节点需要唤醒(CAS 修改 state 成功后再次 check),实现“一次 release,唤醒多个等待者”的传播效果

















