semaphore 是 java 并发包中用于控制并发访问数量的同步工具,本质是许可计数器,通过 acquire() 和 release() 管理许可,支持多线程并发进入,适用于单机轻量级接口限流,需注意许可泄漏、异步释放及集群扩展问题。

Semaphore 是 Java 并发包中用于控制并发访问数量的同步工具,特别适合在高并发场景下对核心接口做简单、轻量的流量限流(非精确限流,但响应快、开销小)。
理解 Semaphore 的核心作用
Semaphore 本质是一个“许可计数器”,通过 acquire() 获取许可、release() 归还许可来控制同时允许多少线程执行某段代码。它不关心线程身份,只关注当前剩余许可数。
与 synchronized 或 ReentrantLock 不同,Semaphore 支持“多个线程同时进入”,适合限制并发数(如最多 10 个请求同时处理),而非互斥访问单个资源。
在接口限流中使用 Semaphore 的典型方式
将 Semaphore 实例作为类成员变量(建议 final 修饰),在接口方法入口处尝试获取许可;获取失败则快速失败(如返回 429 或降级响应),避免排队阻塞。
- 初始化时指定许可总数,例如 new Semaphore(20) 表示最多 20 个并发请求能进入业务逻辑
- 使用 tryAcquire() 配合超时参数(如 tryAcquire(1, TimeUnit.MILLISECONDS)),避免无限等待
- 务必在 finally 块中 release(),确保许可及时归还,否则会导致“许可泄漏”和限流失效
- 注意:Semaphore 不是线程安全的“计数器替代品”,它不保证公平性(默认非公平),若需严格 FIFO 可启用公平模式 new Semaphore(20, true)
一个 Spring Boot 接口限流示例
以 Controller 层为例,用成员变量 Semaphore 控制 /order/create 接口并发数:
private final Semaphore orderLimit = new Semaphore(50); // 允许最多 50 并发
@PostMapping("/order/create")
public ResponseEntity<string> createOrder(@RequestBody OrderRequest req) {
if (!orderLimit.tryAcquire()) {
return ResponseEntity.status(429).body("请求过于频繁,请稍后再试");
}
try {
// 执行实际下单逻辑(DB、RPC 等)
orderService.placeOrder(req);
return ResponseEntity.ok("下单成功");
} finally {
orderLimit.release(); // 必须释放
}
}</string>
注意:该方式适用于单机限流。集群环境下需配合 Redis + Lua 或专门的限流中间件(如 Sentinel)实现分布式限流。
使用时的关键注意事项
Semaphore 限流简单高效,但有明显边界条件需规避:
- 不要在异步回调或 CompletableFuture 中直接 release —— 线程可能已切换,应在原始调用线程中配对 release
- 避免在 acquire 失败后仍执行耗时操作(如日志记录大量字段),否则会削弱限流效果
- 动态调整许可数较难(setPermits 是 package-private),如需运行时调参,可封装一层代理或改用 Resilience4j 等框架
- 与熔断、降级配合使用更稳妥:限流失败后可触发 fallback 逻辑,而非简单抛异常
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











