java.util.concurrent.Semaphore 是一个用于控制对一组资源的访问的同步辅助类。它可以看作是一个计数器,用于管理对资源的访问许可数量。下面是一个简单的例子,展示了如何使用 Semaphore 来控制对一组资源的访问。 假设我们有一个资源池,比如一个包含 5 个资源(比如 5 台打印机)的系统,我们希望限制同时访问这些资源的线程数量。我们可以使用 Semaphore 来实现这一点。
Semaphore 事例
import java.util.concurrent.Semaphore;
public class SemaphoreTemp {
private final int numberOfResources;
private final Semaphore semaphore;
public SemaphoreTemp(int numberOfResources) {
this.numberOfResources = numberOfResources;
this.semaphore = new Semaphore(numberOfResources);
}
public void accessResource(String threadName) {
try {
// 请求一个许可
semaphore.acquire();
System.out.println(threadName + " has acquired a resource.");
// 模拟资源使用
Thread.sleep((int) (Math.random() * 1000));
System.out.println(threadName + " is releasing the resource.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println(threadName + " was interrupted while waiting for a resource.");
} finally {
// 释放许可
semaphore.release();
}
}
public void 打印机(String threadName) {
try {
// 请求一个许可
semaphore.acquire();
System.out.println(threadName + " has acquired a 打印机.");
// 模拟资源使用
Thread.sleep((int) (Math.random() * 1000));
System.out.println(threadName + " is releasing the 打印机.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println(threadName + " was interrupted while waiting for a 打印机.");
} finally {
// 释放许可
semaphore.release();
}
}
public static void main(String[] args) {
int numberOfResources = 5;
SemaphoreTemp resourcePool = new SemaphoreTemp(numberOfResources);
// 创建并启动多个线程来访问资源
for (int i = 0; i < 10; i++) {
int threadNumber = i + 1;
if(i%2==0){
new Thread(() -> resourcePool.accessResource("Thread-" + threadNumber)).start();
}
else {
new Thread(() -> resourcePool.打印机("Thread-" + threadNumber)).start();
}
}
}
}
解释
- ResourcePool 类:
numberOfResources
变量表示资源池中资源的数量。semaphore
是一个Semaphore
实例,初始化为numberOfResources
。这意味着最多可以有numberOfResources
个线程同时获取许可并访问资源。
- accessResource 方法:
- 使用
semaphore.acquire()
方法请求一个许可。如果当前没有可用的许可,线程将被阻塞,直到有许可可用。 - 模拟资源使用,通过
Thread.sleep
方法让线程暂停一段时间。 - 使用
semaphore.release()
方法释放许可,以便其他线程可以获取许可并访问资源。
- 使用
-
打印机 方法 同accessResource 方法一致,共有5个资源
- main 方法:
- 创建一个
ResourcePool
实例,资源数量为 5。 - 启动 10 个线程,每个线程都尝试访问资源。由于资源池只有 5 个资源,最多只能有 5 个线程同时访问资源,其他线程将被阻塞,直到有资源可用。
- 创建一个
运行结果
运行这个程序,你会看到类似以下的输出(输出顺序可能会有所不同):
Thread-5 has acquired a resource.
Thread-7 has acquired a resource.
Thread-6 has acquired a 打印机.
Thread-4 has acquired a 打印机.
Thread-10 has acquired a 打印机.
Thread-7 is releasing the resource.
Thread-1 has acquired a resource.
Thread-6 is releasing the 打印机.
Thread-2 has acquired a 打印机.
Thread-2 is releasing the 打印机.
Thread-3 has acquired a resource.
Thread-5 is releasing the resource.
Thread-9 has acquired a resource.
Thread-4 is releasing the 打印机.
Thread-8 has acquired a 打印机.
Thread-8 is releasing the 打印机.
Thread-3 is releasing the resource.
Thread-10 is releasing the 打印机.
Thread-1 is releasing the resource.
Thread-9 is releasing the resource.
通过这种方式,Semaphore 确保在任何时候,最多只有 numberOfResources=5个线程可以访问资源。
其他方法
带参数的acquire方法 尝试获取指定数量的许可。 semaphore.acquire(2); // 获取2个许可
tryAcquire方法 尝试获取许可,如果许可立即可用,则获取许可并返回true,否则返回false。 boolean success = semaphore.tryAcquire();
带超时的tryAcquire方法 尝试在给定的等待时间内获取许可。 boolean success = semaphore.tryAcquire(10, TimeUnit.SECONDS); // 最多等待10秒
带参数的release方法 释放指定数量的许可。 semaphore.release(2); // 释放2个许可 availablePermits方法 返回当前可用的许可数量。 int permits = semaphore.availablePermits();