1、CountDownLatch實現(xiàn)
CountDownLatch的實現(xiàn)基于AQS的共享模式,其Sync實現(xiàn)如下:
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
//初始的count值,state中保存此count值
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
//嘗試獲取共享鎖,只有當state為0時,即計數(shù)值為0時才能獲取到共享鎖
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//嘗試釋放共享鎖,通過CAS的方式將state即count值減一
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
CountDownLatch總體流程分三部:
鎖計數(shù)值初始化:即初始化state值為鎖的count值;
await過程:await時會調用tryAcquireShared()獲取共享鎖,若此時state值為大于0,則會將當前線程節(jié)點插入同步隊列尾部,并阻塞當前線程;
countDown過程:countDown時會tryReleaseShared()無阻塞地減少鎖計數(shù)值,當鎖計數(shù)值減少到0時,就會喚醒同步隊列中阻塞的線程節(jié)點。
2、CyclicBarrier實現(xiàn)
CyclicBarrier是基于ReentrantLock和Condition實現(xiàn)的鎖工具。
實現(xiàn)源碼:
//構造函數(shù),parties為初始化的計數(shù)器,barrierAction為當parties計數(shù)減到0時的回調
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
//初始計數(shù)
this.parties = parties;
//本輪計數(shù)值
this.count = parties;
//計數(shù)為0時的回調
this.barrierCommand = barrierAction;
}
//等待
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
//h獲取鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
//獲取當前分代
final Generation g = generation;
//此次分代已被停止?
if (g.broken)
throw new BrokenBarrierException();
//當前線程被終止?
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
//分代計數(shù)值減1,若計數(shù)值減到0,則運行回調,并調用nextGeneration()
//喚醒所有在等待的線程,同時更新分代信息
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
//計數(shù)值未減到0,則需要等待
for (;;) {
try {
//無時間條件等待
if (!timed)
trip.await();
//設置了超時時間等待
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
//等待的過程中分代已經停止,則拋出異常
//原可能是某個線程在等待的過程中線程被中斷
if (g.broken)
throw new BrokenBarrierException();
//分代已經更新?說明是被signal信號喚醒的
if (g != generation)
return index;
//等待超時?
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
3、Semaphore實現(xiàn)
Semaphore的實現(xiàn)是基于AQS的共享鎖,有公平和非公平兩種模式。
基本的Sync實現(xiàn):
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
//初始的許可數(shù)量,同步鎖的state保存許可的數(shù)量
Sync(int permits) {
setState(permits);
}
//獲取許可數(shù)量
final int getPermits() {
return getState();
}
//非公平的方式獲取共享鎖
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
//可用許可數(shù)減去需求的許可數(shù)
int remaining = available - acquires;
//許可數(shù)大于0時,CAS獲取許可
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
//釋放許可
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
//許可數(shù)加鎖釋放的許可數(shù)
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
//CAS更新許可,直到成功
if (compareAndSetState(current, next))
return true;
}
}
//減少許可
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
//
if (compareAndSetState(current, next))
return;
}
}
//將許可消耗完
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}
公平的FairSync實現(xiàn)::
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
//公平方式獲取許可
protected int tryAcquireShared(int acquires) {
for (;;) {
//當前節(jié)點有前驅節(jié)點,則獲取失敗
if (hasQueuedPredecessors())
return -1;
//無前驅節(jié)點時,CAS方式獲取許可
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
}
非公平的Sync實現(xiàn):
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
//直接使用Sync的nonfairTryAcquireShared()實現(xiàn),非公平方式獲取許可
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
相關對外接口實現(xiàn):
//信號量初始化,permits:初始許可數(shù);fire:是否公平
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
//獲取許可
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//釋放許可
public void release() {
sync.releaseShared(1);
}
4、特性對比
區(qū)別:
CountDownLatch 使一個線程A或是組線程A等待其它線程執(zhí)行完畢后,線程A或是組線程A才繼續(xù)執(zhí)行。CyclicBarrier:一組線程使用await()指定barrier,所有線程都到達各自的barrier后,再同時執(zhí)行各自barrier下面的代碼。Semaphore:是用來控制同時訪問特定資源的線程數(shù)量,它通過協(xié)調各個線程,以保證合理的使用公共資源。
CountDownLatch是減計數(shù)方式,計數(shù)==0時釋放所有等待的線程;CyclicBarrier是加計數(shù)方式,計數(shù)達到構造方法中參數(shù)指定的值時釋放所有等待的線程。Semaphore,每次semaphore.acquire(),獲取一個資源,每次semaphore.acquire(n),獲取n個資源,當達到semaphore 指定資源數(shù)量時就不能再訪問線程處于阻塞,必須等其它線程釋放資源,semaphore.relase()每次資源一個資源,semaphore.relase(n)每次資源n個資源。
CountDownLatch當計數(shù)到0時,計數(shù)無法被重置;CyclicBarrier計數(shù)達到指定值時,計數(shù)置為0重新開始。
CountDownLatch每次調用countDown()方法計數(shù)減一,調用await()方法只進行阻塞,對計數(shù)沒任何影響;CyclicBarrier只有一個await()方法,調用await()方法計數(shù)加1,若加1后的值不等于構造方法的值,則線程阻塞。
CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數(shù)的構造方法。CountDownLatch、CyclikBarrier這個值作為計數(shù)用,達到該次數(shù)即釋放等待的線程,而Semaphore 中所有acquire獲取到的資源達到這個數(shù),會使得其它線程阻塞。
共同:
CountDownLatch與CyclikBarrier兩者的共同點是都具有await()方法,并且執(zhí)行此方法會引起線程的阻塞,達到某種條件才能繼續(xù)執(zhí)行(這種條件也是兩者的不同)。Semaphore,acquire方獲取的資源達到最大數(shù)量時,線程再次acquire獲取資源時,也會使線程處于阻塞狀態(tài)。CountDownLatch與CyclikBarrier兩者的共同點是都具有await()方法,并且執(zhí)行此方法會引起線程的阻塞,達到某種條件才能繼續(xù)執(zhí)行(這種條件也是兩者的不同)。Semaphore,acquire方獲取的資源達到最大數(shù)量時,線程再次acquire獲取資源時,也會使線程處于阻塞狀態(tài)。CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數(shù)的構造方法。
CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數(shù)的構造方法。
CountdownLatch和CyclicBarrier的區(qū)別:
CountDownLatch簡單的說就是一個線程等待,直到他所等待的其他線程都執(zhí)行完成并且調用countDown()方法發(fā)出通知后,當前線程才可以繼續(xù)執(zhí)行。
CyclicBarrier是所有線程都進行等待,直到所有線程都準備好進入await()方法之后,所有線程同時開始執(zhí)行!
CountDownLatch的計數(shù)器只能使用一次。而CyclicBarrier的計數(shù)器可以使用reset() 方法重置。所以CyclicBarrier能處理更為復雜的業(yè)務場景,比如如果計算發(fā)生錯誤,可以重置計數(shù)器,并讓線程們重新執(zhí)行一次。
Semaphore:
Semaphore翻譯成字面意思為 信號量,Semaphore可以控同時訪問的線程個數(shù),通過 acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。