返回
多路并发下的Semaphore:JUC之AQS
见解分享
2023-10-26 15:22:43
在Java并发编程中,synchronized
是一种常用的同步机制,它提供互斥锁语义,确保同一时刻只有一个线程可以获取执行代码的锁。然而,在某些场景下,我们需要使用多把锁来协调多个线程之间的访问,此时 Semaphore
就派上用场了。
Semaphore
Semaphore(信号量)是一种用于限制对共享资源访问数量的同步器。它允许指定数量的线程同时访问该资源,超过该数量的线程将被阻塞。
在Java中,Semaphore 被实现为 java.util.concurrent.Semaphore
类,它基于 AQS (AbstractQueuedSynchronizer)框架构建。AQS 是一个同步队列,它使用一个队列来管理等待获取锁的线程。
Semaphore 的工作原理
Semaphore 使用一个整数值 permits
来表示可用的许可证数量。当一个线程想要获取一个许可证时,它会调用 acquire()
方法。如果 permits
大于 0,该线程将获得许可证并继续执行。否则,该线程将被阻塞,直到有许可证可用。
当一个线程完成对资源的访问后,它会调用 release()
方法来释放许可证。这会增加 permits
的值,从而允许另一个线程获取许可证。
Semaphore 的特性
- 公平性: AQS 框架保证了线程获取许可证的公平性,即先请求的线程将优先获取许可证。
- 可重入性: 同一个线程可以多次获取同一个许可证,而不会被阻塞。
- 超时: 我们可以设置一个超时时间,如果在指定时间内没有获取到许可证,则抛出异常。
Semaphore 的应用场景
Semaphore 有着广泛的应用场景,例如:
- 资源池管理: 限制对资源池中资源的并发访问数量。
- 限流: 控制对服务的并发请求数量。
- 多线程协调: 协调多个线程之间的访问顺序。
Semaphore 的示例
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private static final Semaphore semaphore = new Semaphore(3);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
// 获取许可证
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 获得许可证");
// 模拟资源访问
Thread.sleep(1000);
// 释放许可证
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
在示例中:
- 我们创建了一个具有 3 个许可证的 Semaphore。
- 10 个线程同时并发执行,试图获取许可证。
- 只有 3 个线程可以同时获取许可证,其余线程将被阻塞。
- 当线程完成资源访问后,它们释放许可证,允许其他线程继续执行。