semaphore是jvm内轻量级并发控制工具,仅限单机场景使用,适用于内部管理接口、强依赖第三方系统等低qps稳定场景,需正确初始化、配对acquire/release、放在真正耗资源位置,并可叠加失败统计实现简易熔断。

Semaphore 是 JVM 内轻量级并发控制工具,靠许可(permit)数量限制同一时刻能执行业务逻辑的线程数,适用于单机场景下的快速限流,但不解决分布式、自适应或跨线程池协调问题。
明确适用边界:别用在不该用的地方
它只在当前 JVM 进程内有效。比如部署 3 台服务,每台都 new Semaphore(5),实际总并发就是 15,不是 5。它不能替代 Redis + Lua 或 Sentinel 等集中式方案。如果你的服务是云原生多副本、有弹性扩缩容需求,或者接口 QPS 经常超过 50,就该换分布式限流方案。
典型适合场景包括:
- 内部管理接口(如后台导出、定时任务触发的批量操作)
- 调用强依赖型第三方系统(如核心保险系统),且对方明确要求单机最多并发 3~5 路
- 不想引入额外中间件、对限流精度要求不高、QPS 稳定低于 10 的轻量服务
正确初始化与安全使用:避免许可泄漏
必须确保 Semaphore 实例全局唯一、生命周期与应用一致:
- Spring 环境下声明为 @Bean,禁止每次 new 新对象
- acquire() 和 release() 必须由同一线程配对;不能在 CompletableFuture 或 @Async 中 acquire 后,回主线程 release
- 所有 acquire() 后必须紧跟 try-finally 块,在 finally 中调用 release(),否则异常中断会导致许可永久丢失
- 优先用 tryAcquire(long timeout, TimeUnit unit),超时建议设 100~300ms,防止线程池被阻塞耗尽
把限流点放在真正耗资源的位置
不要在 Controller 入口就做许可检查。鉴权、参数校验、日志记录这些轻量逻辑应放在线程获取许可之前;只把真正消耗资源的操作(如远程 HTTP 调用、数据库写入、大文件生成)包进临界区。
否则会出现“空转占许可”现象——请求卡在非关键路径上,却白白占用并发额度,降低整体吞吐效率。
叠加失败统计实现简易熔断
Semaphore 本身不带熔断能力,但可配合状态机模拟:
- 用 AtomicInteger 统计最近 60 秒内的失败请求数和总请求数
- 失败率超阈值(如 50%)且总请求数 ≥20,将开关置为 OPEN
- OPEN 状态下直接拒绝请求(跳过 tryAcquire),持续 30 秒后进入 HALF-OPEN,仅放行 1~2 个试探请求
- 试探成功则恢复服务,失败则重置计时器
这种组合形成“限流 + 熔断”双控机制,虽不如 Hystrix 或 Resilience4j 完整,但在单机轻量场景中足够实用。











