Semaphore通过acquire()和release()实现“先占后放”的许可配对机制,构造时指定的许可总数即为最大并发线程数,acquire阻塞等待可用许可,release唤醒等待线程,务必在finally中调用以避免泄漏。

Semaphore 通过 acquire() 获取许可、release() 归还许可,形成“先占后放”的配对机制,从而硬性限制同时进入临界区的线程数量。许可总数在构造时固定,acquire 成功即扣减,release 执行即加回,系统据此动态调度等待线程。
acquire() 是并发闸门
每次调用 acquire(),线程尝试获取一个(或多个)许可:
- 若当前有可用许可,立即获得并继续执行,内部许可数减 1
- 若无可用许可,线程阻塞,进入 AQS 等待队列,直到其他线程 release 后被唤醒
- 支持重载:acquire(int n) 可一次性申请多个许可,适合批量资源占用场景
- 注意捕获 InterruptedException,尤其在线程可能被中断的环境中
release() 是许可归还关键
release() 必须与 acquire() 成对出现,否则许可泄漏会导致后续线程永久阻塞:
- 每次调用 release(),内部许可数加 1,并唤醒等待队列中的一个线程(公平模式)或任意一个(非公平模式)
- 务必放在 finally 块中,确保异常时也能释放,例如:
try { ... } finally { semaphore.release(); } - 支持 release(int n),用于匹配此前 acquire(n) 的批量操作
许可数与并发上限直接对应
初始化时传入的整数值,就是最大并发线程数:
立即学习“Java免费学习笔记(深入)”;
- new Semaphore(3) → 最多 3 个线程能同时执行受保护代码
- 第 4 个线程调用 acquire() 会阻塞,直到前 3 个中任一调用 release()
- availablePermits() 可实时查看剩余许可数,便于监控或调试
- 许可数可大于 1,但不能为负;release 超出初始值不会报错,只是让可用数虚高(一般不建议)
公平性影响线程调度顺序
是否启用公平模式,决定等待线程获取许可的优先级:
- 非公平模式(默认):允许“插队”,刚 release 的许可可能被新来的线程抢走,吞吐更高
- 公平模式:new Semaphore(3, true),严格按等待时间排序,避免饥饿,但性能略低
- 公平性只影响 acquire 阻塞后的唤醒顺序,不影响许可总数和基本限流效果


















