semaphore 通过可配置许可计数器控制并发线程数,acquire/release 原子操作确保安全;许可数需合理设置并配合超时获取、精准包围耗资源操作及失败统计熔断机制。

Semaphore 不是分配“权限”,而是管理“许可”——它通过一个可配置的计数器,控制同一时刻能进入临界区的线程数量,从而提升资源利用率,避免过载。
许可计数器决定并发上限
初始化时指定的 permits 数值,就是最大并发数。比如 new Semaphore(4) 表示最多 4 个线程能同时执行受保护逻辑。计数器在 acquire() 时减 1,在 release() 时加 1,全程原子操作,无竞态风险。
- 许可数设得太小:资源闲置,吞吐上不去
- 许可数设得太大:起不到限流作用,可能压垮下游(如 DB 连接池、第三方 API)
- 合理值通常参考下游资源容量,例如数据库连接池大小为 20,Semaphore 可设为 15~18,留出缓冲余量
只保护真正耗资源的操作
把 acquire() 和 release() 包围在核心动作周围,而非整个接口入口。轻量逻辑(鉴权、日志、参数校验)应放在许可检查之前。
- 错误做法:Controller 层一进来就
tryAcquire(),结果参数校验失败也占着许可 - 正确做法:校验通过后、调用远程服务前 acquire;远程返回后、组装响应前 release
- 这样许可不被空转占用,单位时间内能处理更多有效请求
带超时的非阻塞获取更健壮
避免线程无限等待导致线程池耗尽。优先使用 tryAcquire(long timeout, TimeUnit unit),超时建议设 100–300ms。
- 超时返回 false,可快速失败并返回降级响应(如缓存数据、默认值)
- 配合
finally块确保 release 调用不遗漏,防止许可泄漏 - 不要依赖
acquireUninterruptibly()或无参acquire(),生产环境风险高
结合失败统计实现简易熔断
Semaphore 本身不熔断,但可用原子计数器 + 时间窗口模拟:
- 用
AtomicInteger记录最近 60 秒总请求数和失败数 - 失败率 ≥50% 且总请求数 ≥20,开关切到 OPEN 状态
- OPEN 状态下直接拒绝新请求(跳过 acquire),30 秒后进 HALF-OPEN,只放行少量试探请求
- 试探成功则恢复,失败则重置熔断计时器











