Semaphore基于AQS共享模式,以state为许可计数器,通过CAS原子操作实现acquire/release;支持公平与非公平策略,依赖AQS队列管理线程阻塞与唤醒。

Semaphore 借助 AQS(AbstractQueuedSynchronizer)控制并发访问量,核心在于把“许可数量”映射为 AQS 的 state 值,并利用其共享模式的同步机制实现线程排队与原子操作。
state 作为许可计数器
AQS 的 volatile int state 字段直接表示当前可用的许可证数量。初始化时传入的 permits 就是 state 的初始值。每次调用 acquire(),本质是执行 AQS 的 tryAcquireShared() —— 尝试用 CAS 将 state 原子地减 1;成功则获取许可,失败则进入同步队列等待。同理,release() 调用 tryReleaseShared(),用 CAS 将 state 原子地加 1,并唤醒等待队列中的线程。
共享模式支撑多线程并发
不同于 ReentrantLock 使用独占模式(一次只放行一个线程),Semaphore 基于 AQS 的 共享模式 实现。这意味着:
- 多个线程可同时成功获取许可(只要 state ≥ 所需数量)
- 释放许可后,AQS 会唤醒所有处于共享等待状态的线程,由它们竞争获取(非公平)或按顺序获取(公平)
- state 可被多个线程“共同消费”,不绑定具体持有者,任意线程都能
release()
公平性由 Sync 子类决定
Semaphore 内部定义了两个 Sync 实现:
立即学习“Java免费学习笔记(深入)”;
-
NonfairSync(默认):在
tryAcquireShared()中跳过队列检查,新线程可直接尝试 CAS 获取许可,吞吐高但可能造成等待线程饥饿 -
FairSync:先调用
hasQueuedPredecessors()判断队列中是否有更早等待的线程;只有队列为空或自己排最前时才尝试获取,确保 FIFO 公平性
阻塞与唤醒依赖 AQS 队列管理
当线程调用 acquire() 但 state 不足时,AQS 会将其封装为 Node 加入同步队列,并挂起线程。一旦其他线程调用 release() 使 state 增加,AQS 就从队头开始传播唤醒信号 —— 在共享模式下,它会持续唤醒后续可获取许可的节点,直到 state 耗尽或队列遍历完成。


















