semaphore本质是并发流量闸门,通过许可计数器限制同时执行线程数,如new semaphore(10)控制最多10个线程访问数据库,超量线程阻塞等待,许可可动态增减,需配合finally释放防泄漏。

Semaphore 不是“权限管理”工具,它不涉及用户身份、角色或访问控制;它是一种并发控制机制,用来限制同时执行的线程数量——本质是流量闸门,不是权限门禁。
Semaphore 的真实作用:控制并发执行数
它通过维护一个许可计数器(permits),决定多少个线程能“通行”进入临界区或执行关键操作。比如数据库连接池最多支持 10 个并发连接,就用 new Semaphore(10);超过的线程会阻塞等待,直到有许可被释放。
- 许可数设为 1 → 效果类似互斥锁(但不可重入)
- 许可数大于 1 → 允许多个线程并行,上限可控
- 许可数可动态增减(任意线程调用
release()都能增加计数)
与线程池协作的关键逻辑
线程池负责“有多少线程可用”,Semaphore 负责“有多少任务能真正跑起来”。二者分工明确:
- 线程池大小(如 20 个线程)决定资源调度能力
- Semaphore 许可数(如 5 个)决定同一时刻最多 5 个任务在执行业务逻辑
- 其余 15 个线程可能处于 acquire() 阻塞状态,不消耗 CPU,但占用线程对象
这种组合特别适合 IO 密集型场景:线程不忙于计算,而是等待网络/磁盘响应,用 Semaphore 控制下游资源(如 API 限流、DB 连接)更精准。
正确使用的三个要点
常见错误集中在资源释放和异常处理上:
- release() 必须放在 finally 块中:否则一旦业务抛异常,许可无法归还,导致后续所有线程永久阻塞
- 避免 tryAcquire() 忘记释放:若用带超时或非阻塞版本获取许可,成功才需 release;失败时不许 release,否则会虚增许可数
-
慎用公平模式:
new Semaphore(5, true)保证先到先得,但会降低吞吐量;高并发下默认非公平更实用
典型应用场景举例
不是所有并发都需要 Semaphore,但它在以下情况不可替代:
- 调用外部 HTTP 接口,对方限流 10 QPS → 用
acquire()控制并发请求数 - 批量写文件,磁盘 I/O 容易成为瓶颈 → 限制同时写入的线程数,避免争抢
- 模拟有限资源池,如 8 个虚拟设备供 50 个任务轮用 → Semaphore 替代手动计数+同步块
它不替代 synchronized 或 ReentrantLock,也不替代 RateLimiter;它是轻量、灵活、面向“数量上限”的并发协调器。











