Semaphore
Semaphore 是信号量的意思,一般用来控制同时访问某个资源的线程数量,协调各个线程合理的访问公共资源,Semaphore 的底层依赖的是 AQS。
Semaphore 使用计数器来控制对共享资源的访问, 如果计数器大于0,则表示允许访问共享资源, 如果为 0,则表示共享资源已经达到访问的上限就拒绝访问, 计数器的计数的就是允许同时访问共享资源的线程数。
知识储备传送门:
深入理解 AbstractQueuedSynchronizer(AQS)【源码分析】
深入理解 ReentrantLock 【源码分析】
CAS的使用以及底层原理详解
深入理解 CountDownLatch 【源码分析】
Semaphore 的应用场景:
控制并发量,通常用于那些资源有明确访问数量限制的场景,常用于限流 ,比如停车场场景,停车场内部车位有限,同时只能停有限车辆,比如窗口办业务场景,窗口有限,同时只能有限的人同时办业务。
Semaphore 使用简单举例:
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2);
for (int a = 0; a < 4; a++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("当前线程获取许可,线程名称:" + Thread.currentThread().getName() + ";当前时间:" + System.currentTimeMillis() / 1000);
Thread.sleep(2000);
semaphore.release();
System.out.println("当前线程释放许可,线程名称:" + Thread.currentThread().getName() + ";当前时间:" + System.currentTimeMillis() / 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
}).start();
}
}
执行结果:
当前线程获取许可,线程名称:Thread-0;当前时间:1712322271
当前线程获取许可,线程名称:Thread-1;当前时间:1712322271
当前线程释放许可,线程名称:Thread-0;当前时间:1712322273
当前线程获取许可,线程名称:Thread-3;当前时间:1712322273
当前线程获取许可,线程名称:Thread-2;当前时间:1712322273
当前线程释放许可,线程名称:Thread-1;当前时间:1712322273
当前线程释放许可,线程名称:Thread-2;当前时间:1712322275
当前线程释放许可,线程名称:Thread-3;当前时间:1712322275
执行结果分析:
我们的案例代码是想同时启动 4 个线程,Semaphore 只有两个信号量,我们发现 1712322271 时候,有两个线程获取了许可,执行了业务代码,1712322273 时刻有两个线程释放了许可,同时另外两个线程才获取到许可,开始执行业务代码,达到了使用 Semaphore 信号量控制并发的目的。
Semaphore 常用方法:
- acquire() :获取一个执行许可,在获取到执行许可之前或者被其他线程中断之前,线程一直会被阻塞。
- acquire(int permits) :获取 permits 个执行许可,在获取到执行许可之前或者被其他线程中断之前,线程一直会被阻塞。
- acquireUninterruptibly() :获取一个执行许可,在获取到执行许可之前(忽略中断),线程一直会被阻塞。
- tryAcquire() :尝试获取一个执行许可,返回获取的结果,线程不会