semaphore是java并发包中用于控制同时访问资源的线程数量的同步工具,通过许可机制实现限流与资源池化,支持公平/非公平模式,需配对使用acquire()和release()确保正确性。

Semaphore 是 Java 并发包(java.util.concurrent)中用于控制**同时访问某资源的线程数量**的同步工具。它不关心“谁”在用,只管“最多几个能用”,特别适合做限流、池化资源(如数据库连接池)、避免系统过载等场景。
初始化 Semaphore:指定许可数量
创建时传入一个整数参数,表示当前可用的“许可”(permits)总数。这个值就是并发线程的上限。
例如,限制最多 3 个线程同时执行某段代码:
Semaphore semaphore = new Semaphore(3);
还可以选择是否启用公平模式(按等待顺序分配许可),默认非公平(性能更好):
Semaphore semaphore = new Semaphore(3, true); // 公平模式
获取许可:acquire() 和 tryAcquire()
线程要进入受保护的临界区前,必须先获取一个许可。获取不到就阻塞(或超时/失败)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
acquire():阻塞直到拿到许可(可能被中断) -
acquireUninterruptibly():阻塞获取,不响应中断 -
tryAcquire():立即尝试,成功返回true,失败返回false -
tryAcquire(long timeout, TimeUnit unit):带超时,避免无限等待
推荐在业务逻辑中配合 try-finally 确保释放:
semaphore.acquire(); // 或 tryAcquire(...)
try {
// 执行受限操作,如调用外部接口、写文件、访问慢资源
} finally {
semaphore.release(); // 必须释放!否则许可会永久丢失
}
释放许可:release() 是关键
每次 acquire() 成功后,必须有且仅有一次对应的 release(),否则许可数会持续减少,最终所有线程都卡住。
注意点:
-
release()不要求调用线程必须是之前获取许可的那个线程(这点和ReentrantLock不同) - 可以一次释放多个许可:
semaphore.release(2) - 如果误调用多次
release(),许可数可能超过初始值(但通常无害,只是放宽了限制)
实际使用示例:模拟 API 调用限流
假设你有一个高频调用的第三方接口,对方限流为每秒最多 5 次请求:
Semaphore apiLimit = new Semaphore(5);
public void callExternalApi() throws InterruptedException {
if (apiLimit.tryAcquire(1, 1, TimeUnit.SECONDS)) {
try {
// 实际调用 HTTP 接口
System.out.println("Calling API... " + Thread.currentThread().getName());
Thread.sleep(100); // 模拟网络延迟
} finally {
apiLimit.release(); // 一定要放在这里
}
} else {
System.out.println("Request rejected: limit exceeded");
}
}
这样就能确保任意时刻最多 5 个线程在调用该接口,超出的线程要么等待、要么直接拒绝,避免触发对方限流熔断。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










