semaphore 通过许可计数实时限制单机并发线程数,需共享 static final 实例、贴近真实开销处 acquire/release、必用 try-finally 防泄漏、加超时避免线程阻塞,仅适用于单机限流。

用 Semaphore 限制线程并发数,关键是靠“许可计数”硬性卡住同时执行的线程数量,不是靠时间窗口或历史统计,而是实时盯住“此刻有几个在跑”。它轻量、零依赖、响应快,适合单机内保护连接池、文件句柄、第三方调用等有限资源。
初始化一个全局复用的 Semaphore 实例
限流对象必须跨线程共享,不能每次请求都 new 一个:
- 声明为 static final,确保所有线程竞争同一许可池
- 构造参数即最大并发数,例如
new Semaphore(5)表示最多 5 个线程可并行执行受控逻辑 - 默认非公平模式(性能更好),除非业务强依赖请求顺序,否则不用传
true
在真正耗资源的位置配对 acquire 和 release
许可获取点要贴近实际开销操作,避免空转占坑:
- 不要在 Controller 入口就
acquire(),而应在调用远程接口、执行 SQL 或读写大文件前才申请 - 必须用 try-finally 包裹业务逻辑,
release()放在 finally 块中,防止异常导致许可泄漏 - 释放许可不要求是同一个线程,但必须保证每次
acquire()后有且仅有一次release()
生产环境务必加超时,避免线程被拖垮
无超时的 acquire() 可能让 Tomcat 或 Netty 工作线程无限等待,最终耗尽连接池:
- 改用
tryAcquire(1, 200, MILLISECONDS),超时建议设 100–300ms - 超时后直接返回 429 或抛业务异常,不进入后续逻辑
- 拒绝请求比卡住线程更安全,也利于上游快速失败重试
注意它的能力边界:只在单机有效
Semaphore 是 JVM 内部同步工具,天然不具备分布式能力:
- 部署 3 台服务,每台都配
new Semaphore(5),实际总并发就是 15,不是 5 - 若需集群级限流,必须上层引入 Redis + Lua、Sentinel 或网关统一限流
- 它适合内部管理接口、低 QPS 定时任务、强依赖型老核心系统调用等轻量稳定场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











