Semaphore通过许可证控制对象创建的并发数而非总数,需在创建前acquire、成功后release,并用try-finally防泄露;initialCount和maximumCount决定节流强度,公平性影响排队顺序但不改变平均速率,应配合超时和中断避免死等。

Semaphore 的“门票”思想,本质是用许可证(permit)作为访问资源的准入凭证。它不直接控制对象创建本身,而是通过限制**同时能执行创建逻辑的线程数量**,间接调控对象生成的速率。关键点在于:许可证管的是“并发执行权”,不是“对象总数”或“创建动作是否发生”。
许可证如何绑定到对象创建流程
要让 Semaphore 控制对象创建速率,需将 acquire() 和 release() 显式嵌入创建逻辑中:
- 在 new 对象或调用工厂方法前,先调用 semaphore.acquire() —— 没有门票,线程就停在这儿等
- 对象成功创建(且完成必要初始化)后,再调用 semaphore.release() —— 归还门票,腾出名额给下一个线程
- 若创建过程可能失败(如构造异常),必须用 try-finally 或 try-with-resources 确保 release() 总被执行,否则许可证泄露,后续线程永久阻塞
初始值与最大值决定“节流强度”
构造 Semaphore 时传入的两个参数直接影响速率控制效果:
- initialCount:初始可用许可证数,即系统启动时允许多少线程立刻开始创建对象(例如设为 0,表示所有创建请求都需等待主线程统一放行)
- maximumCount:许可证上限,也是同一时刻最多有几个线程能并行执行创建逻辑;设为 5,就相当于“最多 5 张并发门票”,哪怕有 100 个线程排队,也只准 5 个同时开工
- 注意:initialCount 不能超过 maximumCount,也不能为负;maximumCount 必须 ≥ 1
公平性影响排队秩序,但不改变平均速率
是否启用公平模式(fair = true)决定了线程获取许可证的顺序:
- 公平模式下,先到的线程先得票,适合对响应时间敏感、要求可预测延迟的场景
- 非公平模式(默认)允许插队,吞吐量略高,但个别线程可能长时间等待
- 无论哪种,单位时间内释放的许可证总数不变,因此长期平均创建速率由 release() 调用频率和 maximumCount 共同约束
配合超时与中断,避免死等
生产环境不应让线程无限期等待许可证:
- 用 tryAcquire(long timeout, TimeUnit unit) 替代 acquire(),设置合理超时(如 3 秒),超时未拿到票就放弃创建,防止雪崩
- 捕获 InterruptedException 并正确处理(如清理资源、记录日志),确保线程可被外部中断,提升系统可控性
- 不建议在创建逻辑里忽略中断信号,否则会破坏 JVM 的协作中断机制

















