Semaphore主要用于单机并发数控制,通过许可证桶模型限制JVM内同时执行关键逻辑的线程数,适用于后台导出、调用强依赖第三方接口等场景,不跨实例,不替代分布式限流方案。

Semaphore 在 Java 高并发系统中主要用于单机维度的**并发数控制**,而非全局限流或频次限流。它通过“许可证桶”模型限制同一时刻能执行关键业务逻辑的线程数量,适合轻量、低 QPS、无分布式协调需求的场景。
适用场景与边界要清楚
它只在当前 JVM 进程内生效,不跨实例、不跨机器。比如部署 5 台服务,每台配置 new Semaphore(4),实际总并发上限是 20,不是 4。因此:
- 适合内部管理接口(如后台导出、定时批量任务)
- 适合强依赖第三方系统(如银行/保险核心接口),对方明确要求单机并发 ≤3~5
- 不适合 Web API 全局限流、用户级配额、每分钟 100 次这类滑动窗口需求
- 不替代 Redis + Lua 或 Sentinel 等分布式方案
初始化与线程安全使用是关键
用错方式会导致许可泄漏、线程阻塞甚至服务假死:
- Spring 环境下必须声明为
@Bean,确保全局唯一、生命周期与应用一致 -
acquire()和release()必须由同一线程完成,禁止在@Async或CompletableFuture中获取后回主线程释放 - 所有
acquire()后必须紧跟try-finally,且release()写在finally块中 - 优先使用
tryAcquire(1, 100, TimeUnit.MILLISECONDS),避免无限等待耗尽 Tomcat 线程池
限流点要落在真正耗资源的位置
别一进 Controller 就抢许可。鉴权、参数校验、日志这些轻量操作应放在许可检查之前:
立即学习“Java免费学习笔记(深入)”;
- 把
tryAcquire()放在调第三方 HTTP、写数据库、生成大文件等操作前 - 否则请求卡在非关键路径上却占着许可证,“空转占配额”,吞吐反而下降
- 举例:一个导出接口,先校验权限和参数(不占许可),再
tryAcquire(),成功后再查库+生成 Excel
可叠加失败统计实现简易熔断
Semaphore 本身不带熔断,但配合原子计数器能模拟基础状态机:
- 用
AtomicInteger统计最近 60 秒失败数与总请求数 - 失败率超 50% 且总请求数 ≥20,切换为 OPEN 状态
- OPEN 状态下直接拒绝(跳过
tryAcquire),30 秒后进入 HALF-OPEN,只放行 1~2 个试探请求 - 试探成功则恢复,失败则重置计时器
不复杂但容易忽略


















