semaphore是java并发包中用于控制同时访问资源的线程数量的同步工具,通过许可计数器实现限流,支持acquire/release操作、公平模式、非阻塞尝试及批量许可管理,适用于连接池、api限流等场景。

Semaphore 是 Java 并发包(java.util.concurrent)中用于控制**同时访问某资源的线程数量**的同步工具,特别适合管理固定数量的共享资源(比如数据库连接池、线程池任务槽、API 调用配额等)。
理解 Semaphore 的核心概念
Semaphore 内部维护一个许可(permit)计数器。构造时指定初始许可数量(即最大并发数):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- acquire():尝试获取一个许可;若当前许可数 > 0,则立即获得并减 1;否则线程阻塞等待(可选带超时或中断响应的版本)。
- release():释放一个许可,计数器 +1,可能唤醒等待中的线程。
- 它不关心“谁获取了”,只管总数——所以不是锁,而是“流量控制器”。
基本用法示例:限制最多 3 个线程同时执行某段代码
下面是一个模拟“限流访问共享文件”的例子:
<font color="#888"><pre class="brush:php;toolbar:false;">import java.util.concurrent.Semaphore;
public class FileAccessExample {
private static final Semaphore semaphore = new Semaphore(3); // 最多 3 个并发访问
public static void accessFile(String fileName) {
try {
semaphore.acquire(); // 获取许可(阻塞直到有空闲)
System.out.println(Thread.currentThread().getName() + " 开始访问 " + fileName);
Thread.sleep(2000); // 模拟耗时操作
System.out.println(Thread.currentThread().getName() + " 完成访问 " + fileName);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release(); // 务必在 finally 中释放!
}
}
public static void main(String[] args) {
for (int i = 0; i accessFile("data.txt")).start();
}
}
}
运行时会看到:任意时刻最多只有 3 个线程打印“开始访问”,其余线程在 acquire() 处等待,等有线程调用 release() 后才继续。
进阶技巧与注意事项
-
公平性选择:构造时传入
true可启用公平模式(FIFO 等待队列),避免饥饿,但性能略低:new Semaphore(3, true)。 -
尝试获取(非阻塞):用
tryAcquire()判断是否能立即获得许可,适合做快速失败或降级逻辑。 -
批量许可:支持一次获取/释放多个许可,如
acquire(2)或release(3),适用于资源按组分配的场景。 - 务必保证 release 在 finally 块中执行,否则一旦异常跳过释放,许可数永久减少,导致后续线程永远阻塞。
- 注意与 ReentrantLock 的区别:Semaphore 不要求 acquire 和 release 在同一线程执行;它也不具备重入性(同一个线程多次 acquire 需要对应多次 release)。
典型应用场景
- 连接池管理(如限制同时打开的数据库连接数)
- 对外部服务的并发调用限流(防止打垮第三方 API)
- 模拟有限硬件资源(如打印机、GPU 显存槽位)的争用
- 配合 CountDownLatch 或 CyclicBarrier 实现更复杂的协同调度
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










