acquire() 通过 cas 原子递减 aqs 的 state(许可证数),若减后 ≥0 则成功获取,否则阻塞;其本质是 tryacquireshared 的 cas 尝试。

acquire() 是对 state 的原子递减操作
Semaphore 内部用 AQS 的 state 字段表示当前可用许可证数量。调用 acquire() 时,底层执行的是 tryAcquireShared(acquires),其核心逻辑是 CAS(Compare-And-Swap)尝试将 state 原子地减去请求的许可数(默认为 1)。
若减后结果 ≥ 0,说明有足够许可,线程立即获得准入;若结果 LockSupport.park() 进入阻塞状态——这个“阻塞”不是操作系统级挂起,而是线程在用户态自旋 + park 的混合机制,由 JVM 和 AQS 协同控制。
release() 是对 state 的原子递增与唤醒联动
release() 对应 tryReleaseShared(releases),同样基于 CAS:读取当前 state,计算 next = current + releases,再尝试用 CAS 将 state 更新为 next。
成功后,AQS 会立即触发 doReleaseShared(),该方法从同步队列头节点开始,尝试唤醒一个或多个处于 park 状态的等待线程——注意:不是“广播唤醒全部”,而是逐个检查、唤醒就绪者,且唤醒行为本身也通过 CAS 控制,避免竞争冲突。
被唤醒的线程回到 tryAcquireShared 循环中重新竞争 state,形成“归还 → 唤醒 → 再尝试获取”的闭环。
凭证流转不经过内存拷贝,只反映在 state 变化与队列节点状态上
所谓“凭证”并非真实对象或引用,它完全抽象为 AQS 中的一个整型计数器(state)。没有对象创建、没有堆内存分配、没有跨线程传递实体。
- acquire 成功:仅 state 减少,无新对象;失败则新建 Node 节点插入队列尾部
- release 执行:仅 state 增加,无对象销毁;但可能触发已有 Node 节点的状态变更(如 waitStatus 从 SIGNAL → 0)和线程 unpark
- 队列中的每个 Node 实际只存线程引用、前后指针、waitStatus 标志位,不携带任何“凭证副本”
公平性差异体现在入队与唤醒时机,而非凭证本身
非公平模式下,新线程调用 acquire 时会先抢一次 CAS —— 即使队列里有人排队,也可能插队成功;公平模式则强制所有线程都必须先入队,再按 FIFO 顺序被唤醒。
但无论哪种模式,凭证的物理存在形式始终只是 state 值。公平性影响的是线程获取凭证的调度顺序,而不是凭证如何存储或转移。










