semaphore的acquire()是按需扣减许可的阻塞操作,原子递减state计数器,成功则进入临界区,失败则入队挂起;acquire(int)一次性申请多许可,不支持部分获取;公平模式下严格fifo排队;必须配对release以防许可泄漏或溢出。

Semaphore 的 acquire() 方法本质是“按需扣减许可”的阻塞式获取操作,核心逻辑围绕许可计数器(state)的原子递减与线程排队机制展开。它不分配资源,只控制准入——就像停车场入口的栏杆,有空位才抬杆,没空位就排队等。
acquire() 的执行流程
调用 acquire() 时,Semaphore 会尝试将内部许可计数器(AQS 的 state)原子地减 1:
- 若减法成功(即原值 ≥ 1),线程立即通过,进入临界区
- 若减法失败(即原值为 0),当前线程被封装为 Node 加入 AQS 同步队列,并挂起(park)等待
- 一旦其他线程调用
release()增加许可,AQS 会唤醒队首等待线程,该线程重新尝试获取许可
acquire(int permits) 的关键差异
这个重载方法不是“多次调用 acquire()”,而是一次性申请多个许可,其行为更严格:
- 必须满足
currentPermits ≥ permits才能成功获取,否则整个请求阻塞 - 不会部分成功(例如有 2 个空闲许可却申请 3 个,结果是全部等待,而不是先拿走 2 个)
- 适用于需要批量资源的场景,比如一次读取 4KB 数据块、启动一组协同线程等
公平性对 acquire 的影响
构造时传入 true 启用公平模式后,acquire() 行为发生关键变化:
- 非公平模式:允许插队,新线程可能抢在已等待线程之前获取许可(吞吐更高,但可能饥饿)
- 公平模式:严格 FIFO,所有 acquire 请求按调用顺序排队,先到先得(响应更可预测,但吞吐略低)
- 注意:公平性只影响等待队列中的调度,不影响许可是否足够这一前提判断
务必配对 release 的原因
acquire() 和 release() 必须成对出现,否则许可池会持续枯竭:
- 遗漏
release()→ 许可数永久减少 → 后续线程无限等待 - 多调用
release()→ 许可数超过初始值 → 失去限流意义(但不会报错) - 最佳实践:总在
finally块中调用release(),确保异常时也能归还











