1 Semaphore简介及使用
ps:要想理解Semaphore原理,需要先了解AQS,不了解AQS的可以看先之前的文章->aqs源码解析
Semaphore类是一个计数信号量,必须由获取它的线程释放,底层是基于AQS实现的,通常用于限制可以访问某些资源(物理或逻辑的)线程数目。
举个例子,某个停车场总共有5个停车位,意味着同一时刻最多只能容纳5辆车,先来的5辆车占了车位之后,其他的车只能等待或者离开。下面是代码演示:
public class SemaphoreDemo {
public static void main(String[] args) {
// 初始化 相当于5个车位
Semaphore semaphore = new Semaphore(5);
// 10辆车同时抢占车位
for (int i=0; i<10; i++){
new Car(i, semaphore).start();
}
}
static class Car extends Thread{
private Integer num;
private Semaphore semaphore;
public Car(Integer num, Semaphore semaphore){
this.num = num;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("第" + num +"辆车 抢占一个车位 ");
TimeUnit.SECONDS.sleep(1);
System.out.println("第" + num +"辆车 开走了 ");
semaphore.release();
}catch (InterruptedException e){
}
}
}
}
运行结果:
同一时刻最多容纳5辆车,当车位释放时,才可以有新的车去抢占车位。
2 源码分析
2.1 Semaphore初始化
Sync(int permits) {
setState(permits);
}
当通过构造初始化的时候,调用setState对state变量进行赋值,这个state相当于车位数(限流数)
2.2 acquire方法
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 尝试获取车位
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
// 获取限流数
int available = getState();
// 可用车位 - 本次获取车位 = 剩余可用车位
int remaining = available - acquires;
if (remaining < 0 ||
// cas方式对变量进行修改
compareAndSetState(available, remaining))
return remaining;
}
}
调用acquire方法,默认每次值获取一个共享资源(相当于车位),通过自旋 + cas的方式,修改剩余可用共享资源的个数。
2.3 release方法
public void release() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
// 尝试释放资源
if (tryReleaseShared(arg)) {
// 如果释放成功 则唤醒等待队列中的线程
doReleaseShared();
return true;
}
return false;
}
protected final boolean tryReleaseShared(int releases) {
// 自旋 + cas 的方式修改资源数
for (;;) {
// 获取当前state
int current = getState();
// 基数本次释放后 state的值
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
// 修改
if (compareAndSetState(current, next))
return true;
}
}
调用release方法进行释放资源,通过修改state的值进行释放资源,如果释放成功后,唤醒等待队列中的线程去竞争资源。