目录
定义
Semaphore(信号量)是Java并发编程中的一个同步工具类,用于控制对共享资源的访问。它通过维护一个计数器来管理多个线程对资源的并发访问数量。这个计数器表示当前可用的许可数,每当一个线程获取资源时,计数器减一;当线程释放资源时,计数器加一。如果计数器为零,则任何试图获取许可的线程都会被阻塞,直到有其他线程释放许可为止。
使用方法
Semaphore提供了几个关键方法:
acquire()
: 尝试获取一个许可。如果没有可用的许可,调用此方法的线程将被阻塞,直到有许可被释放。release()
: 释放一个许可,增加可用的许可数量。如果有线程因为调用acquire()
而阻塞,那么这些线程将有机会继续执行。tryAcquire()
: 尝试立即获取一个许可,如果成功则返回true,否则返回false。availablePermits()
: 返回当前可用的许可数量。
主要用途
Semaphore的主要用途包括:
- 限制资源的并发访问:例如,限制数据库连接池的大小,确保同时只有固定数量的线程可以访问数据库。
- 实现限流:例如,限制某个服务的并发请求数量,防止系统过载。
- 实现生产者-消费者模式:通过两个Semaphore对象,一个用于控制空槽的数量,另一个用于控制满槽的数量,从而实现生产者和消费者的协调。
- 控制并发任务的数量:例如,限制同时运行的任务数量,避免系统资源耗尽。
使用场景示例
假设我们有一个文件服务器,需要限制同时读写文件的数量。我们可以使用Semaphore来实现这一需求。
import java.util.concurrent.Semaphore;
public class FileServer {
private final Semaphore semaphore;
public FileServer(int maxConcurrentReads) {
// 初始化信号量,最大并发读操作数为maxConcurrentReads
this.semaphore = new Semaphore(maxConcurrentReads);
}
public void readFile(String fileName) {
try {
// 尝试获取一个许可
semaphore.acquire();
System.out.println("Reading file: " + fileName);
// 模拟读取文件的操作
Thread.sleep((long) (Math.random() * 1000));
System.out.println("Finished reading file: " + fileName);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放许可
semaphore.release();
}
}
public static void main(String[] args) {
FileServer server = new FileServer(3); // 允许最多3个并发读操作
for (int i = 0; i < 10; i++) {
final int fileIndex = i;
new Thread(() -> server.readFile("file" + fileIndex)).start();
}
}
}
在这个示例中,我们创建了一个FileServer
类,其中包含一个Semaphore对象。构造函数接受一个参数maxConcurrentReads
,表示允许的最大并发读操作数。在readFile
方法中,我们使用acquire()
方法尝试获取一个许可,如果成功则进行文件读取操作,完成后使用release()
方法释放许可。这样就能确保同时只有最多maxConcurrentReads
个线程在进行文件读取操作。