Semaphore通过许可计数机制控制并发线程数,初始化指定总许可数(如5),acquire获取、release归还,必须成对且用try-finally保障;推荐超时获取避免无限等待;公平模式仅在需FIFO时启用;适用于N选M场景如连接池、API限流,非互斥场景。

Semaphore 通过“许可计数”机制精确控制并发线程数,不是锁住资源不让别人进,而是发有限的“入场券”——有多少张券,就允许多少个线程同时干活。
核心是许可数量与 acquire/release 配对
初始化时指定总许可数(比如 new Semaphore(5)),代表最多 5 个线程能并行访问该资源。每个线程必须先调用 acquire() 拿到一张券才能进入,用完必须在 finally 块中调用 release() 归还,否则券永远少一张,后续线程会卡死。
- 许可不绑定线程:谁拿谁还,但必须成对;
- 没券时
acquire()阻塞,直到别人归还; - 务必用 try-finally 包裹,哪怕操作中途抛异常也要释放;
- 全局共享同一个 Semaphore 实例(如 static final 或 Spring Bean),否则形同虚设。
避免无限等待,用超时获取更稳妥
生产环境别用无参 acquire(),它可能永远等下去。推荐用 tryAcquire(long timeout, TimeUnit unit):
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 返回
true表示成功拿到许可,可继续执行; - 返回
false表示超时未获取,应走降级逻辑(如返回缓存、记录告警、拒绝请求); - 若被中断,会抛
InterruptedException,需调用Thread.currentThread().interrupt()恢复中断状态,不可吞掉。
按需选择公平性,多数场景用默认非公平
构造时可传第二个参数 fair = true 启用公平模式,让等待久的线程优先获取许可。但这会增加调度开销、降低吞吐量。
立即学习“Java免费学习笔记(深入)”;
- 普通限流(如 API 调用配额、打印机任务)用默认非公平即可;
- 仅当业务强依赖执行顺序(如订单扣库存需严格 FIFO)才考虑公平模式;
- 公平性不影响许可总数,只影响分配顺序。
典型适用场景与常见误区
Semaphore 不是替代 synchronized 的通用锁,它的价值在于「N 选 M」式并发控制:
- 适合:数据库连接池上限、硬件设备(打印机/串口)并发访问、第三方 API 每秒调用配额、文件句柄复用;
- 不适合:保护单个变量或代码块的互斥访问(此时用 ReentrantLock 更轻量);
- 注意:不要在
acquire()前做耗时操作(如查 DB、远程调用),否则券被占着却没干活,浪费并发能力; - 警惕线程池 + Semaphore 组合:10 个线程的池配 Semaphore(2),实际并发仍只有 2,别误以为线程数等于并发数。

















