请编写一个示例程序展示如何使用 Semaphore 类控制对共享资源的并发访问数量。
示例程序:使用 Semaphore
控制对共享资源的并发访问数量
以下程序模拟了多个线程对一个共享资源(例如数据库连接)的访问,同时通过 Semaphore
限制并发访问数量为 3。
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
// 创建一个信号量,限制最多允许 3 个线程访问共享资源
private static final Semaphore semaphore = new Semaphore(3);
public static void main(String[] args) {
// 创建多个线程模拟并发访问
for (int i = 1; i <= 10; i++) {
new Thread(new Task(i)).start();
}
}
// 模拟任务类,每个线程访问共享资源
static class Task implements Runnable {
private final int threadId;
public Task(int threadId) {
this.threadId = threadId;
}
@Override
public void run() {
try {
System.out.println("Thread " + threadId + " is waiting for access.");
// 获取许可
semaphore.acquire();
System.out.println("Thread " + threadId + " has acquired access.");
// 模拟访问共享资源
Thread.sleep((long) (Math.random() * 5000)); // 模拟耗时操作
System.out.println("Thread " + threadId + " is releasing access.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 释放许可
semaphore.release();
}
}
}
}
输出示例
程序输出可能如下(具体顺序可能因线程调度而异):
Thread 1 is waiting for access.
Thread 2 is waiting for access.
Thread 3 is waiting for access.
Thread 4 is waiting for access.
Thread 5 is waiting for access.
Thread 1 has acquired access.
Thread 2 has acquired access.
Thread 3 has acquired access.
Thread 1 is releasing access.
Thread 4 has acquired access.
Thread 3 is releasing access.
Thread 5 has acquired access.
Thread 2 is releasing access.
Thread 6 is waiting for access.
Thread 6 has acquired access.
Thread 4 is releasing access.
...
程序说明
Semaphore
创建:Semaphore semaphore = new Semaphore(3);
:限制最多 3 个线程同时访问共享资源。
acquire()
方法:- 当一个线程调用
acquire()
时,如果信号量许可(permits
)数量大于 0,则获取许可并进入临界区。 - 如果信号量许可为 0,线程会阻塞,直到有线程释放许可。
- 当一个线程调用
release()
方法:- 调用
release()
后,释放一个许可,并唤醒一个等待线程(如果有)。
- 调用
- 模拟共享资源访问:
- 在临界区中,线程调用
Thread.sleep()
模拟访问耗时。
- 在临界区中,线程调用
- 线程调度:
- 由于线程调度的随机性,不同线程的访问顺序可能不同,但始终确保同时最多有 3 个线程访问共享资源。
应用场景
- 数据库连接池:
- 限制同时访问数据库的线程数量,避免超出数据库连接的限制。
- 限流控制:
- 在高并发系统中,限制访问某些服务或资源的线程数量,防止系统过载。
- 多线程下载:
- 限制同时进行的文件下载任务数量。