Semaphore通过原子计数器控制并发线程数,不解决授权而解决资源争用;性能取决于许可数设置(建议下游资源70%~90%)、公平性模式(非公平吞吐高,公平确定性强)、acquire/release范围(仅包裹耗资源操作)及超时与finally释放机制。

Semaphore 的许可管理不是“分配权限”,而是通过一个原子计数器控制并发线程进入临界区的数量。它不解决逻辑授权问题,只解决资源争用问题;性能影响不来自信号量本身,而来自许可数设置、模式选择、使用位置和异常处理方式这四个关键环节。
许可数量直接影响吞吐与稳定性
许可数是最大并发上限,必须与下游资源容量匹配:
- 设得太小(如数据库连接池为20,Semaphore却设为5)→ 线程大量排队,CPU空转,吞吐上不去
- 设得太大(如设为100)→ 失去限流意义,可能瞬间打满DB连接或第三方API,引发雪崩
- 合理值通常取下游瓶颈资源的70%~90%,例如连接池大小20,Semaphore建议设15~18,留出缓冲余量
公平性模式决定调度行为与吞吐差异
公平模式(new Semaphore(permits, true))按FIFO排队,非公平模式(默认)允许插队:
- 非公平:吞吐更高,响应延迟更低,适合Web接口、短耗时任务等高并发场景
- 公平:避免线程饥饿,响应时间更稳定,适合金融交易、配额类系统等对确定性要求高的场景
- 高竞争下,非公平减少队列维护开销,上下文切换更少;公平模式因等待队列同步成本,吞吐通常低10%~20%
acquire/release 包围范围决定许可利用率
许可应只保护真正耗资源的操作,而非整个请求生命周期:
立即学习“Java免费学习笔记(深入)”;
- 错误做法:Controller入口就 acquire → 参数校验失败、鉴权拒绝也占着许可,造成空转浪费
- 正确做法:校验通过后、调用远程服务前 acquire;远程返回后、组装响应前 release
- 轻量操作(日志、DTO转换、参数校验)一律放在许可检查之外,单位时间内可处理更多有效请求
超时机制与异常保障决定系统健壮性
生产环境禁用无参 acquire(),必须配合超时与 finally 释放:
- 优先用 tryAcquire(100, TimeUnit.MILLISECONDS),超时返回 false 后可快速降级(如返回缓存、默认值)
- 阻塞式 acquire() 易耗尽Tomcat线程池,导致整体请求堆积甚至503
- release() 必须放在 finally 块中,否则异常、超时、中断都会导致许可泄漏,最终许可证归零、服务不可用



















