本文章详细介绍了Java多线程编程中的信号量(Semaphore)机制,并通过具体示例代码深入浅出地讲解了其应用场景和使用方法。
**JAVA 多线程之信号量Semaphore实例详解**
在Java多线程编程中,信号量Semaphore是一种非常重要的同步工具,用于控制对公共资源的访问。Semaphore类位于`java.util.concurrent`包下,它允许我们限制同时访问特定资源的线程数量。
### Semaphore简介
信号量是一个计数器,用于管理对有限资源的并发访问。它可以视为一种许可证,每当一个线程想要访问公共资源时,都需要先获取一个许可证。如果许可证可用,线程就能继续执行;如果许可证不可用,线程会被阻塞,直到其他线程释放一个许可证。
### 单值与多值信号量
Semaphore有两种类型:二进制信号量(单值)和多值信号量。二进制信号量仅允许一个线程持有许可证,通常用于实现互斥锁。多值信号量允许多个线程同时持有许可证,可以指定一个初始化的许可数量。
### 信号量的概念
以停车场为例,信号量就像看门人,它维护着停车位的数量。如果有多个车辆同时到达,看门人会根据当前空闲的停车位数量决定哪些车辆可以进入,其余车辆则需要等待。当车辆离开时,看门人会增加可用的停车位,进而允许更多车辆进入。
### 信号量的操作
在信号量上,有两个关键操作:
1. **acquire()**:线程尝试获取一个许可证。如果许可证可用,许可证数量减1,线程继续执行;否则,线程被阻塞,直到有其他线程释放许可证。
2. **release()**:线程释放一个许可证,许可证数量加1,这可能会唤醒一个等待的线程。
### 公平与非公平模式
Semaphore提供了一种选择,可以创建公平或非公平的信号量。在公平模式下,线程按照等待的顺序获取许可证,遵循先进先出(FIFO)原则。而在非公平模式下,线程获取许可证没有特定顺序,可能造成某些线程长时间等待。
### Java中的Semaphore
Java的Semaphore类提供了以下构造方法:
```java
Semaphore(int permits) 创建指定数量的许可证的非公平信号量
Semaphore(int permits, boolean fair) 创建指定数量的许可证的信号量,并指定是否为公平模式
```
### 代码示例
下面是一个简单的Semaphore使用示例,模拟了5个资源(停车位)供20个线程(车辆)共享的情况:
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaPhore {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semp = new Semaphore(5); // 5个许可证
for (int index = 0; index < 50; index++) {
final int NO = index;
exec.execute(new Runnable() {
@Override
public void run() {
try {
semp.acquire(); // 尝试获取许可证
System.out.println(线程 + NO + 进入);
模拟执行任务
Thread.sleep(1000);
System.out.println(线程 + NO + 退出);
semp.release(); // 任务完成后释放许可证
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
exec.shutdown();
}
}
```
在这个例子中,线程池创建了20个线程,但Semaphore限制了最多只有5个线程可以同时执行任务。当一个线程完成任务并释放许可证后,等待的线程会有一个获得许可证并开始执行。
### 应用场景
Semaphore常用于以下场景:
1. **限制并发访问**: 如控制数据库连接池的最大并发连接数。
2. **资源池管理**: 如多线程下载时限制同时下载的任务数量。
3. **死锁恢复**: 通过线程间交换许可证,有时可以帮助解除死锁状态。
Semaphore是Java多线程编程中一种强大的同步工具,它提供了灵活的许可管理机制,帮助开发者有效地控制并发访问,防止资源过度消耗,提高系统的稳定性。