java semaphore 源码_Java并发工具类Semaphore源码剖析

本篇文章的主要内容:

1:举例说明Semaphore

2:Semaphore的原理剖析

3:Semaphore的源码剖析

1:举例说明Semaphorepublic class SemaphoreTest {

private static Semaphore sh = new Semaphore(3);

public static void main(String[] args) {

for (int i = 0; i < 10; i++) {

int finalI = i;

new Thread(() -> {

try {

sh.acquire();

String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

System.out.println("Thread-" + (finalI + 1) + "获取运行权限:" + dateStr);

Thread.sleep(1000);

sh.release();

} catch (Exception e) {

e.printStackTrace();

}

}).start();

}

}

}

运行结果如下图:

b88e2b5b579a5c018ca1b9eb4f51f403.png

通过上面的运行结果,会发现一个规律,那就是一次最多有三个线程同时运行,在看上面的demo,我们在创建Semaphore的时候传递了参数3,这两者似乎存在着联系,我们可以大胆的猜想。

创建Semaphore对象传递的参数决定了多少个线程能够同时获取资源,然后执行代码逻辑。

我们对Java并发包中的AQS框架非常的熟悉了,这个类的原理似乎和AQS中共享资源的获取和释放非常的类似,我们首先回顾一下这个知识点。

1:state<0:表示获取资源失败

2:state==0:表示获取资源成功,但是没有剩余的资源了

3:state>0:表示获取资源成功,并且还有剩余的资源

在创建Semaphore时传递的参数就是state,我们传递3,说明同时能够有3个线程获取到资源,其他线程需要等待,直到其他线程释放资源。

2:Semaphore的原理剖析

通过上面的demo,大家是否对Semaphore的用法有所了解了,它的内部原理其实就是AQS中的共享模式下对资源的获取和释放。

1:创建Semaphore时传递的参数,底层赋值给了AQS的共享资源state

2:Semaphore中的acquire()方法其实就是尝试获取资源,如果还有剩余的资源,则代表获取了锁,就可以继续执行了,如果没有剩余的资源,那么这个线程就会放入CLH等待队列,等待有资源。

3:Semaphore中的release()方法就是释放资源。

通过上面的介绍,对Semaphore总结一句话:同一个时间允许多少个线程获取到共享资源,获取到资源的线程能够继续执行代码逻辑,没有获取到资源的线程则需要等待了,直到有共享资源或者被其他线程中断。

结合上面的例子,开始进行详细的分析,可能上面的demo执行结果有所不同,因为多线程下,哪个线程获取到CPU,哪个线程首先执行,但是相同的就是同一时间最多有3个线程同时执行。

1:Thread2首先获取到了CPU的执行权,此时共享资源是3,所以Thread2获取到了资源,并且将资源数量-1,此时共享资源是2

2:Thread3获取到了CPU的执行权,此时共享资源是2,所以Thread3获取到了资源,并且将资源数量-1,此时共享资源是1

3:Thread1获取到了CPU的执行权,此时共享资源是1,所以Thread1获取到了资源,并且将资源数量-1,此时共享资源0.

4:Thread5获取到了CPU的执行权,此时共享资源是0,所以Thread5获取资源失败,那么Thread5就是封装成Node节点存放到CLH等待队列中。

5:下面的线程以此类推。

上面的步骤仅仅是一种情况,可能Thread5获取CPU后,Thread2已经释放了资源,但是不管怎样,因为只有3个共享资源,所以同时只能有3个线程获取。

接下来我们从源码角度来看看Semaphore是否像我们上面所说的。

3:Semaphore的源码剖析

通过前几篇文章的学习,我们知道,如果利用AQS框架来实现并发功能,那一定有一个内部类,并且这个内部类继承了AQS,我们搜索Semaphore源码。

4c6e7f6d734ea5ebfc2698831ca37b3f.png

上图中的Sync就是AQS的子类,其中NonfairSync和FairSync是Sync的两个子类,分别对应的是非公平模式和公平模式。

3.1:Semaphore的构造函数

public Semaphore(int permits) {

sync = new NonfairSync(permits);

}

public Semaphore(int permits, boolean fair) {

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

}

第一个参数:permits:表示初始化的共享资源

第二个参数:fair:true:表示公平模式,false:表示非公平模式,默认是非公平模式。

这两个构造函数底层要么调用非公平模式(NonfairSync),要么调用公平模式(FairSync),然后把permits传递进去,那么我们进入NonfairSync

NonfairSync(int permits) {

super(permits);

}

Sync(int permits) {

setState(permits);

}

从上面的代码可以看到Semaphore构造函数最终调用的是Sync的构造函数,而Sync直接调用AQS的setState()方法,将permits赋值给了AQS的共享资源state。

3.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);

}

上面的acquire()方法底层直接调用AQS中的acquireSharedInterruptibly()方法,而这个方法是AQS中共享模式下获取资源的模板方法,而AQS的子类必须实现tryAcquireShared()方法,那么我们接下来到Sync中看看这个方法怎样实现的。以非公平类为例:NonfairSync

final int nonfairTryAcquireShared(int acquires) {

for (;;) {

int available = getState();

int remaining = available - acquires;

if (remaining < 0 ||

compareAndSetState(available, remaining))

return remaining;

}

}

首先是一个for无限循环,然后通过调用AQS的getState()方法获取到可用的共享资源state,然后减去这一次所需要的共享资源,获取到剩余的remaining,然后有两个结果

第一个结果:如果剩余资源remaining<0:说明剩余的资源不足,获取资源失败

第二个结果,如果剩余资源remaining>=0:说明剩余的资源能够满足,获取资源成功,只是当remaining==0时没有剩余的资源了,remaining>0时还有剩余的资源。

f0ba036e0afcdbb6d0b9f69c94ed75c8.png

3.3:release()方法

public void release() {

sync.releaseShared(1);

}

public final boolean releaseShared(int arg) {

if (tryReleaseShared(arg)) {

doReleaseShared();

return true;

}

return false;

}

release()方法底层直接调用了AQS的releaseShared()方法进行释放资源,而这个方法也是一个模板方法,AQS的子类只需要实现tryReleaseShared()即可,那么我们接下来看看Sync是怎样实现这个方法的。

protected final boolean tryReleaseShared(int releases) {

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;

}

}

这个方法首先调用AQS的getState()方法获取到共享资源state,然后联合此次释放的资源releases,通过CAS机制更新state,直到更新成功才返回。

5a1ea4af84c098ad97e47c8256490872.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值