一,底層AQS源碼分析:併發編程(四):AbstractQueuedSynchronizer源碼分析
二,CyclicBarrier介紹
1,線程處理
* CyclicBarrier 的字面意思就是循環屏障。在一組線程到達循環屏障時阻塞,直到最後一個線程到達屏障時,屏障纔會放開,讓所有線程執行。該類可以與 CountDownLatch 進行類比,功能基本一致。不同點在於 CyclicBarrier 的循環概念,CountDownLatch 爲一次性屏障,放開之後不會再對後續線程進行攔截,CyclicBarrier 一次放開之後會把屏障值設置爲初始狀態,循環進行屏障!
2,類圖
* 其實從類圖中不能看到任何有用信息,CyclicBarrier 內部通過 ReentrantLock 和 Condition 進行控制,實現循環屏障
3,常用API
// 初始化重入鎖進行線程加鎖處理
private final ReentrantLock lock = new ReentrantLock();
// 初始化Condition進行線程阻塞和線程喚醒處理
private final Condition trip = lock.newCondition();
// CyclicBarrier初始化許可量
private final int parties;
// 屏障放開前最後一個線程會執行的線程類(爲null不執行)
private final Runnable barrierCommand;
// 表示一個循環屏障週期
private Generation generation = new Generation();
// 初始化CyclicBarrier,並傳遞屏障值
public CyclicBarrier(int parties);
// 初始化CyclicBarrier,並傳遞屏障值和barrierAction
CyclicBarrier(int parties, Runnable barrierAction)
4,功能DEMO
package com.gupao;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @author pj_zhang
* @create 2019-09-15 11:33
*/
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException {
// 初始化 CyclicBarrier,並傳遞count爲3
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
// 因爲初始屏障爲3,但線程數量定位6,所以對於 cyclicBarrier 來說,會有兩次阻塞和兩次釋放
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "正在執行");
// 每一個線程內部等待
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "執行完畢; " + System.currentTimeMillis());
}, "thread_" + i).start();
Thread.sleep(1000);
}
}
}
三,源碼分析
1,初始化
* CyclicBarrier(int parties)
public CyclicBarrier(int parties) {
// 直接通過方法重載調用
this(parties, null);
}
* CyclicBarrier(int parties, Runnable barrierAction)
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
// 初始化屏障前執行線程,沒有則爲空
this.barrierCommand = barrierAction;
}
2,循環屏障
* await(..):無論是顯示等待還是不顯示等待,最終都是殊途同歸,調用同一個底層類
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
* dowait(boolean timed, long nanos)
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// lock:重入鎖,已在常量定義
// 定義語句:private final ReentrantLock lock = new ReentrantLock();
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 賦值當前循環屏障標識
// 可以通過 reset() 方法對標識進行重置
final Generation g = generation;
// 循環屏障中斷
if (g.broken)
throw new BrokenBarrierException();
// 線程中斷處理,
if (Thread.interrupted()) {
// 中斷處理後打破屏障
breakBarrier();
throw new InterruptedException();
}
// 此處表示對循環屏障的屏障值遞減,當減爲0時屏障放開
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 減爲0,表示當前線程是屏障放開前最後一個線程
// 由屏障放開前最後一個線程,執行初始化傳遞的屏障線程
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 構造新的循環屏障,
nextGeneration();
return 0;
} finally {
// 循環屏障釋放異常,則打破屏障
if (!ranAction)
breakBarrier();
}
}
// 前一步沒有放開,說明屏障還需等待,線程阻塞
for (;;) {
try {
// timed判斷是限時阻塞還是直接阻塞
if (!timed)
// trip:Condition,已在常亮定義
// 定義語句:private final Condition trip = lock.newCondition();
trip.await();
else if (nanos > 0L)
// 此處返回剩餘時間
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// 異常後打破屏障
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
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();
}
}
* breakBarrier():打破循環屏障
private void breakBarrier() {
// 設置參數true
generation.broken = true;
// 重置屏障值爲初始值
count = parties;
// 通過Condition喚醒全部阻塞線程進行執行
trip.signalAll();
}
* nextGeneration():說明當前屏障已經阻塞完成,進行下一次循環阻塞
private void nextGeneration() {
// 通過Condition喚醒全部阻塞線程
trip.signalAll();
// 重置屏障值爲初始值
count = parties;
// 構建一個新的Generation,進行下一次循環
generation = new Generation();
}
3,屏障重置
* reset()
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 打破循環屏障,已經被屏障的線程全部喚醒執行
breakBarrier();
// 構建下一個循環屏障
nextGeneration();
} finally {
lock.unlock();
}
}