高级java每日一道面试题-2024年12月28日-并发篇-了解Semaphore吗?
如果有遗漏,评论区告诉我进行补充
面试官: 了解Semaphore吗?
我回答:
在Java高级面试中,Semaphore(信号量)是一个重要的并发控制工具,它用于控制同时访问特定资源的线程数量,以确保资源的合理使用。以下是对Semaphore的详细解析:
一、Semaphore的基本概念
Semaphore(信号量)是一种基于计数的同步机制,它允许多个线程同时访问某个资源池,但会限制可以同时访问该资源的线程数量。Semaphore通过维护一个内部计数器来跟踪当前可用的许可数量,当线程需要访问资源时,它会尝试从Semaphore获取一个许可,如果许可可用,则线程可以继续执行;如果许可不可用,则线程将被阻塞,直到有许可被释放为止。
二、Semaphore的使用场景
Semaphore通常用于那些资源有明确访问数量限制的场景,例如:
- 数据库连接池:同时连接数据库的线程数量有限,当连接数达到限制时,后续的线程需要等待前面的线程释放数据库连接。
- 停车场管理:停车场的车位数量有限,当车位满时,新的车辆需要等待有空位才能进入。
- 文件读写:同时允许并发访问某个文件的线程数量有限,以避免文件损坏或数据不一致。
- 线程池:限制同时运行的任务数量。
- 资源访问控制:如上面的例子所示,限制对特定资源的并发访问。
- 流量控制:在网络编程中,可以用来限制同一时间处理的数据包数量。
三、Semaphore的主要方法
Semaphore提供了几个关键的方法来管理许可:
- acquire():获取一个许可,如果没有可用的许可,则当前线程将被阻塞,直到有许可被释放。
- tryAcquire():尝试获取一个许可,如果没有可用的许可,则立即返回false,而不会阻塞当前线程。
- release():释放一个许可,增加可用许可的数量,并可能唤醒一个正在等待许可的线程。
- availablePermits():返回当前可用的许可数量。
- drainPermits():清空所有可用的许可,返回清空前可用的许可数量。
- reducePermits(int reduction):减少可用许可的数量。
- increasePermits(int increase):增加可用许可的数量。
四、Semaphore的实现原理
Semaphore基于AbstractQueuedSynchronizer(AQS)的共享模式实现。在Semaphore初始化时,会创建一个同步阻塞队列,并将初始的许可数量赋值给队列的state状态。当线程调用acquire方法时,它会尝试从队列中获取一个许可:
- 如果state的值大于0,表示有可用的许可,线程将获取一个许可,并将state的值减1。
- 如果state的值为0,表示没有可用的许可,线程将被阻塞,并加入到一个等待队列中。当有其他线程释放许可时,等待队列中的线程将被唤醒,并尝试重新获取许可。
五、Semaphore的示例代码
以下是一个使用Semaphore的示例代码,用于模拟一个停车场的管理系统:
import java.util.concurrent.Semaphore;
import java.util.Random;
public class TestCar {
// 停车场同时容纳的车辆数量
private static Semaphore semaphore = new Semaphore(10);
public static void main(String[] args) {
// 模拟100辆车进入停车场
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
System.out.println("====" + Thread.currentThread().getName() + "来到停车场");
if (semaphore.availablePermits() == 0) {
System.out.println("车位不足,请耐心等待");
}
semaphore.acquire(); // 获取令牌尝试进入停车场
System.out.println(Thread.currentThread().getName() + "成功进入停车场");
Thread.sleep(new Random().nextInt(10000)); // 模拟车辆在停车场停留的时间
System.out.println(Thread.currentThread().getName() + "驶出停车场");
semaphore.release(); // 释放令牌,腾出停车场车位
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, i + "号车");
thread.start();
}
}
}
在这个示例中,我们创建了一个初始可用资源为10的Semaphore对象,然后模拟了100辆车进入停车场的过程。每辆车都会尝试获取一个许可(即一个车位),如果车位不足,则车辆会被阻塞在停车场入口。当有车辆离开停车场时,会释放一个许可,从而允许新的车辆进入。
六、Semaphore的公平与非公平模式
Semaphore有两种模式:公平模式和非公平模式。
- 公平模式:按照线程调用acquire方法的顺序来获取许可,即先来的线程先获得许可。
- 非公平模式:允许抢占式的获取许可,即后来的线程也有可能先获得许可。
在默认情况下,Semaphore使用的是非公平模式。如果需要公平模式,可以在创建Semaphore对象时传入一个true参数。
总结
Semaphore
是一种强大的同步工具,适用于需要限制并发访问数量的场景。通过合理配置其参数和使用方法,可以有效地管理和优化系统的并发性能。