java 多线程 信号量
时间: 2025-01-04 09:34:28 浏览: 4
### Java 多线程环境中的信号量 (Semaphore) 使用
#### 什么是信号量?
信号量(Semaphore),有时被称为信号灯,在多线程环境下是一种设施,负责协调各个线程,以保证它们能够正确、合理地使用公共资源[^1]。
#### 如何创建和初始化信号量?
`Semaphore` 是 `java.util.concurrent` 包下的一个同步辅助类。通过构造函数可以指定初始的许可数量:
```java
// 创建具有5个许可证的非公平信号量
Semaphore semaphore = new Semaphore(5);
```
如果希望创建的是公平信号量,则可以在构造时传递第二个参数 `true`:
```java
// 创建具有5个许可证的公平信号量
Semaphore fairSemaphore = new Semaphore(5, true);
```
#### 获取和释放许可
为了确保资源的安全访问,线程在进入临界区前应调用 `acquire()` 方法获取许可,并在线程完成其操作后调用 `release()` 方法释放许可。这有助于防止过多的线程同时访问共享资源。
##### 单个许可的操作例子
```java
try {
// 请求单个许可
semaphore.acquire();
try {
// 执行受保护的关键部分代码...
} finally {
// 确保即使发生异常也能释放许可
semaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
```
##### 同时请求多个许可的例子
当需要一次性获得多个许可时,可传入所需的许可数目作为参数给 `acquire(int)` 和 `release(int)` 方法:
```java
int permitsToAcquire = 3;
try {
// 请求三个许可
semaphore.acquire(permitsToAcquire);
try {
// ...处理逻辑...
} finally {
// 释放相同数量的许可
semaphore.release(permitsToAcquire);
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
```
#### 实际应用场景模拟
下面给出一个简单的示例程序,展示如何利用信号量来限制对有限资源的同时访问次数。假设有一个文件服务器只允许最多五个客户端连接上传文件,超过这个限额的新尝试将会被挂起等待其他客户断开连接后再继续。
```java
import java.util.concurrent.Semaphore;
import java.util.Random;
public class FileServer {
private static final int MAX_CONNECTIONS = 5;
private final Semaphore connectionLimiter = new Semaphore(MAX_CONNECTIONS, true);
public void uploadFile(String fileName) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " is trying to connect...");
// 尝试获取许可
connectionLimiter.acquire();
try {
System.out.println(Thread.currentThread().getName() + " connected and uploading file: " + fileName);
// 模拟上传过程
Thread.sleep(new Random().nextInt(2000));
System.out.println(Thread.currentThread().getName() + " finished uploading.");
} finally {
// 断开连接并释放许可
connectionLimiter.release();
System.out.println(Thread.currentThread().getName() + " disconnected from the server.");
}
}
}
class ClientThread extends Thread {
private final String filename;
private final FileServer server;
public ClientThread(FileServer s, String f) {
this.server = s;
this.filename = f;
}
@Override
public void run() {
try {
server.uploadFile(filename);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
// 测试入口点
public class Main {
public static void main(String[] args) {
FileServer fs = new FileServer();
for (int i = 0; i < 8; ++i) {
new ClientThread(fs, "file-" + i).start();
}
}
}
```
在这个案例里,每当一个新的客户端想要开始上传文件的时候就会去申请一个许可;一旦成功获得了许可就可以安全地上载数据而不用担心违反设定的最大并发连接数约束条件。当上载完成后记得要归还所占用的那个许可以便让下一个排队等候的人有机会进来做事[^5]。
阅读全文