java.util.concurrent.Semaphore是一个计数信号量类,维持一个许可集合。每个acquire方法调用如果必要会阻塞直到获得一个可用许可。每个release调用增加一个许可。
在创建时可以传入int permits许可数、boolean fair是否公平,总体结构和可重入锁ReentrantLock类似,内部维持一个Semaphore.Sync类型同步器,有公平模式FairSync、不公平模式NonfairSync两种实现。在构造方法中根据fair创建
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
Semaphore.Sync继承自AbstractQueuedSynchronizer,实现了AbstractQueuedSynchronizer共享模式获取资源,如果不懂AbstractQueuedSynchronizer机制可以返回第一章AbstractQueuedSynchronizer阅读。
Semaphore.Sync 构造时传入permits对应AbstractQueuedSynchronizer的state属性
Sync(int permits) {
setState(permits);
}
Semaphore.acquire(int permits) 实际调用sync的acquireSharedInterruptibly方法,之后state=state-permits;
Semaphore.release(int permits) 则state=state+permits
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
关键方法:
Sync
NonfairSync
FairSync
共享获取资源方式acquireSharedInterruptibly流程和acquireInterruptibly大致相同,以下是aqs中的独占模式流程图,共享模式基本一样就不另外画了。已看过aqs章节的可以略过
acquireShared和acquireSharedInterruptibly的不同点在于线程被中断后acquireSharedInterruptibly抛出InterruptedException异常,而acquireShared忽略中断状态继续执行获取资源循环。
Sync.nonfairTryAcquireShared实现了不公平获取资源的。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {//死循环直至结束
int available = getState();//当前许可数
int remaining = available - acquires;//成功后剩余许可数
//remaining < 0 资源超过限制,返回负数代表不成功
if (remaining < 0 ||
compareAndSetState(available, remaining))//CAS设置剩余资源数,成功返回,不成功继续循环尝试
return remaining;
}
}
NonfairSync.tryAcquireShared直接使用Sync.nonfairTryAcquireShared
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
FairSync.tryAcquireShared方法实现的公平模式稍有不同,区别只在公平模式会判断当前线程之前是否还有等待者,有则直接返回获取失败
protected int tryAcquireShared(int acquires) {
for (;;) {//死循环直至结束
if (hasQueuedPredecessors())//如果当前线程之前还有等待线程,直接返回失败
return -1;
int available = getState();//当前许可数
int remaining = available - acquires;//成功后剩余许可数
//remaining < 0 资源超过限制,返回负数代表不成功
if (remaining < 0 ||
compareAndSetState(available, remaining))//CAS设置剩余资源数,成功返回,不成功继续循环尝试
return remaining;
}
}