首先看他的兩個構造方法:
/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
this(parties, null);
}
有兩個構造方法,parties就是線程數,兩個構造區別就是多了一個Runnable,他的作用就是:
當最後一個線程達到屏障點後,會執行runnable的run方法。
接下來分下核心方法awatit()->dowait(),在此之前先學習下該方法裏幾個成員變量的意思:
ReentrantLock lock = new ReentrantLock();
//條件隊列,當線程到達屏障處時候會阻塞放入到條件隊列裏
Condition trip = lock.newCondition();
//最後一個到達屏障的線程執行的操作
Runnable barrierCommand;
//代,所有線程到達屏障處就是一代,然後生成新一代
private static class Generation {
boolean broken = false;
}
接下來,正式開始:
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 {
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();
}
int index = --count;
if (index == 0) { // tripped
//index=0表示最後一個線程到達了屏障處
boolean ranAction = false;//這裏設置了一個布爾值ranAction,作用是來標識barrierCommand是否被正確執行完畢
try {
final Runnable command = barrierCommand;
//如果構造方法有barrierCommand。則最後一個線程到屏障處要執行run方法
if (command != null)
command.run();
ranAction = true;
//生成新一代,重置count=線程數,喚醒條件隊列裏等待的線程
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
//這裏就是如果到達屏障處,count-1後大於0,則放入到條件隊列
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();
if (g != generation)
//如果是生成了新代,則結束循環
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
源碼看完,這裏終結下流程:
CyclicBarrier的原理就是通過ReentrantLock和Condition來實現的。
當線程執行到await()方法時候,會檢查是否是最後一個到達屏障處線程,如果是則執行構造方法裏的Runnable的run方法,並且生成新代,喚醒條件隊列裏的等待線程。
如果不是最後一個,則直接放入到條件隊列進行等待。
和CountDownLatch區別:
1.計數器是等待所有線程都執行完成,而柵欄是所有線程執行到一半的時候進行等待;
2.計數器的count是不能重置的,而柵欄到0的時候是可以進行重置的。