Semaphore
計數信號量:控制同時訪問某個特定資源的操作數量,或者同時執行某個指定操作的數量,實現某種資源池,對容器施加邊界
acquire
步驟同CountDownLatch.wait
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
//<0才阻塞
for (;;) {
//獲取同步狀態的值。
int available = getState();
int remaining = available - acquires;
//available爲0或者更新成功,直接返回
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
release
public void release() {
sync.releaseShared(1);
}
protected final boolean tryReleaseShared(int releases) {
for (;;) {
//獲取同步狀態的值。
int current = getState();
//累加
int next = current + releases;
//內存溢出,也就是超過了Integer範圍上限
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
//修改值返回
if (compareAndSetState(current, next))
return true;
}
}
總結
與閉鎖和其類似,閉鎖是爲0,纔可以訪問,信號量恰恰相反,
信號量和閉鎖的區別是不是一次性的,可以重複限定多少線程可以訪問資源.
如果不限定釋放的條件,可以不停的釋放從而超過構造設置的許可個數,
建議這樣使用
public boolean add(T o) throws InterruptedException {
//阻塞獲得許可
sem.acquire();
boolean wasAdded = false;
try {
wasAdded = set.add(o);
return wasAdded;
} finally {
//返回許可給信號量
if (!wasAdded)
sem.release();
}
}
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if (wasRemoved)
sem.release();
return wasRemoved;
}