1 概述
通过前面(参考JUC– Semaphore学习(一)简介和使用 )对Semaphore的介绍,我们对Semaphore有了一个基本的认识,我们知道Semaphore通常用于限制对资源使用的线程数量,现在就要针对Semaphore的源码进行分析,Semaphore的结构如下:
从上图我们可以发现,这里又出现了AQS的身影,我们可以看出AQS的重要性。所以再学习JUC的时候非常有必要对AQS的源码有个深入学习。并且这里有公平和非公平两种实现方式。我们接下来会分析是如何实现的。
2 属性
private final Sync sync;
至此我们可以猜想Semaphore的功能实现主要是依靠Sync来实现的,而通过之前对AQS的学习我们知道针对AQS的设计使用了模板方法模式,所以不难想到,这里的Sync里面实现的就是模板方法模式中的基本方法。
3 构造函数
(1)创建指定数量的信号量,默认为非公平模式。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
(2)创建指定数量的信号量,根据指定的公平模式选择同步机制。
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
4 具体方法分析
我们知道针对Semaphore中锁的获取有公平和非公平模式,所以我们这里就针对这两种模式来分别分析两个核心的方法的实现。
4.1 非公平模式(NonfairSync)
acquire()
前面我们已经分析了CountDownLatch和CyclicBarrier的源码。对AQS家族有了个深入的认识。所有在这个地方我们不再分析整个函数的调用链了,直接来查看比较关键的基本函数tryAcquireShared。
直接上源码加注释分析。
protected int tryAcquireShared(int acquires) {
//这里直接调用基类的nonfairTryAcquireShared函数
return nonfairTryAcquireShared(acquires);
}
从上面我们可以看出,这里非公平模式下tryAcquireShared函数事依赖于基类的nonfairTryAcquireShared函数。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
//获取可用许可
int available = getState();
//计算得到当前剩下的可用许可
int remaining = available - acquires;
if (remaining < 0 ||
//使用CAS设置可用许可
compareAndSetState(available, remaining))
return remaining;
}
}
从上面我们可以看出这里其实就是在操作构造函数的初始许可值,只有当余下许可大于0的情况,线程才能得以继续执行。
4.2 公平模式
acquire()
上面我们分析了非公平模式,下面我们来看看公平模式到底是咋个保证公平的呢。
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;
}
}
4.3 释放锁
上面我们针对公平模式和非公平模式分析了锁的获取,由于锁的释放都使用了相同的函数,所以在这个地方我们直接分析锁的释放tryReleaseShared函数。
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");
//使用CAS设置许可
if (compareAndSetState(current, next))
return true;
}
}
上面就是针对Semaphore的源码分析,欢迎大家交流或指正。