【Java】通俗易懂的JUC源码剖析-Semaphore

前言

Semaphore意为信号量,它用来限制某段时间内的最大并发资源数。例如数据库连接池,停车位等。下面通过停车位的栗子来说明Semaphore的使用方式。

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {

private static Semaphore semaphore = new Semaphore(10);

public static void main(String[] args) {

for (int i = 1; i <= 50; i++) {

new Thread(() -> {

try {

if (semaphore.availablePermits() == 0) {

System.out.println("车位已满,需要等待...");

}

semaphore.acquire();

System.out.println("有空余车位,驶进停车场");

// 模拟在停车场smoke or something

Thread.sleep(3000);

System.out.println("老婆喊我回家吃饭,驶出停车场");

semaphore.release();

} catch (InterruptedException e) {

// ignored

}

}).start();

}

}

}

实现原理

看一眼Semaphore的类结构,内部类继承了AQS,同时提供了公平和非公平策略。

【Java】通俗易懂的JUC源码剖析-Semaphore

我们可以在构造函数中指定是公平还是非公平,默认是非公平策略。

public Semaphore(int permits, boolean fair) {

sync = fair ? new FairSync(permits) : new NonfairSync(permits);

}

public Semaphore(int permits) {

sync = new NonfairSync(permits);

}

再来看重要方法(以NonfairSync为例分析):

acquire()

public void acquire() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

可以看到,调用了AQS的模板方法,acquireSharedInterruptibly里面会调用子类重写的tryAcquireShared,来看看相关逻辑:

public final void acquireSharedInterruptibly(int arg)

throws InterruptedException {

if (Thread.interrupted())

throw new InterruptedException();

// 调用子类方法尝试获取共享资源失败,则在队列中阻塞获取

if (tryAcquireShared(arg) < 0)

doAcquireSharedInterruptibly(arg);

}

protected int tryAcquireShared(int acquires) {

return nonfairTryAcquireShared(acquires);

}

final int nonfairTryAcquireShared(int acquires) {

// CAS + 自璇

for (;;) {

// 获取当前剩余资源数

int available = getState();

// 计算获取acquires个资源后,剩余资源数

int remaining = available - acquires;

// 如果不够用或者够用并且CAS设置剩余数成功,则返回

// 否则循环重试CAS操作

if (remaining < 0 ||

compareAndSetState(available, remaining))

return remaining;

}

}

release()

public void release() {

sync.releaseShared(1);

}

同样,release调用了AQS的模板方法,releaseShared里面会调用子类重写的tryReleaseShared方法,来看看子类具体实现逻辑:

protected final boolean tryReleaseShared(int releases) {

// CAS + 自璇

for (;;) {

int current = getState();

int next = current + releases;

if (next < current) // overflow

throw new Error("Maximum permit count exceeded");

if (compareAndSetState(current, next))

return true;

}

}

代码逻辑也很简单,不做赘述。

FairSync公平式的获取,就是在tryAcquireShared时先判断队列中有无在等待的元素,有的话就返回-1,进入同步队列阻塞获取。相关代码如下:

protected int tryAcquireShared(int acquires) {

for (;;) {

if (hasQueuedPredecessors())

return -1;

int available = getState();

int remaining = available - acquires;

if (remaining < 0 ||

compareAndSetState(available, remaining))

return remaining;

}

}

参考资料:

《Java并发编程之美》

以上是 【Java】通俗易懂的JUC源码剖析-Semaphore 的全部内容, 来源链接: utcz.com/a/115083.html

回到顶部