Java中的?CyclicBarrier詳解
CyclicBarrier簡(jiǎn)介
對(duì)于CountDownLatch,其他線(xiàn)程為游戲玩家,比如英雄聯(lián)盟,主線(xiàn)程為控制游戲開(kāi)始的線(xiàn)程。在所有的玩家都準(zhǔn)備好之前,主線(xiàn)程是處于等待狀態(tài)的,也就是游戲不能開(kāi)始。當(dāng)所有的玩家準(zhǔn)備好之后,下一步的動(dòng)作實(shí)施者為主線(xiàn)程,即開(kāi)始游戲。
對(duì)于CyclicBarrier,假設(shè)有一家公司要全體員工進(jìn)行團(tuán)建活動(dòng),活動(dòng)內(nèi)容為翻越三個(gè)障礙物,每一個(gè)人翻越障礙物所用的時(shí)間是不一樣的。但是公司要求所有人在翻越當(dāng)前障礙物之后再開(kāi)始翻越下一個(gè)障礙物,也就是所有人翻越第一個(gè)障礙物之后,才開(kāi)始翻越第二個(gè),以此類(lèi)推。類(lèi)比地,每一個(gè)員工都是一個(gè)“其他線(xiàn)程”。當(dāng)所有人都翻越的所有的障礙物之后,程序才結(jié)束。而主線(xiàn)程可能早就結(jié)束了,這里我們不用管主線(xiàn)程。
CyclicBarrier源碼分析
類(lèi)的繼承關(guān)系
CyclicBarrier沒(méi)有顯示繼承哪個(gè)父類(lèi)或者實(shí)現(xiàn)哪個(gè)父接口, 所有AQS和重入鎖不是通過(guò)繼承實(shí)現(xiàn)的,而是通過(guò)組合實(shí)現(xiàn)的。
public class CyclicBarrier {}
```
### 類(lèi)的內(nèi)部類(lèi)
CyclicBarrier類(lèi)存在一個(gè)內(nèi)部類(lèi)Generation,每一次使用的CycBarrier可以當(dāng)成Generation的實(shí)例,其源代碼如下
```java
private static class Generation {
boolean broken = false;
}說(shuō)明: Generation類(lèi)有一個(gè)屬性broken,用來(lái)表示當(dāng)前屏障是否被損壞。
?類(lèi)的屬性
public class CyclicBarrier {
/** The lock for guarding barrier entry */
// 可重入鎖
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
// 條件隊(duì)列
private final Condition trip = lock.newCondition();
/** The number of parties */
// 參與的線(xiàn)程數(shù)量
private final int parties;
/* The command to run when tripped */
// 由最后一個(gè)進(jìn)入 barrier 的線(xiàn)程執(zhí)行的操作
private final Runnable barrierCommand;
/** The current generation */
// 當(dāng)前代
private Generation generation = new Generation();
// 正在等待進(jìn)入屏障的線(xiàn)程數(shù)量
private int count;
}說(shuō)明: 該屬性有一個(gè)為ReentrantLock對(duì)象,有一個(gè)為Condition對(duì)象,而Condition對(duì)象又是基于AQS的,所以,歸根到底,底層還是由AQS提供支持。
類(lèi)的構(gòu)造函數(shù)
CyclicBarrier(int, Runnable)型構(gòu)造函數(shù)
public CyclicBarrier(int parties, Runnable barrierAction) {
// 參與的線(xiàn)程數(shù)量小于等于0,拋出異常
if (parties <= 0) throw new IllegalArgumentException();
// 設(shè)置parties
this.parties = parties;
// 設(shè)置count
this.count = parties;
// 設(shè)置barrierCommand
this.barrierCommand = barrierAction;
}說(shuō)明: 該構(gòu)造函數(shù)可以指定關(guān)聯(lián)該CyclicBarrier的線(xiàn)程數(shù)量,并且可以指定在所有線(xiàn)程都進(jìn)入屏障后的執(zhí)行動(dòng)作,該執(zhí)行動(dòng)作由最后一個(gè)進(jìn)行屏障的線(xiàn)程執(zhí)行。
CyclicBarrier(int)型構(gòu)造函數(shù)
public CyclicBarrier(int parties) {
// 調(diào)用含有兩個(gè)參數(shù)的構(gòu)造函數(shù)
this(parties, null);
}說(shuō)明: 該構(gòu)造函數(shù)僅僅執(zhí)行了關(guān)聯(lián)該CyclicBarrier的線(xiàn)程數(shù)量,沒(méi)有設(shè)置執(zhí)行動(dòng)作。
核心函數(shù) - dowait函數(shù)
此函數(shù)為CyclicBarrier類(lèi)的核心函數(shù),CyclicBarrier類(lèi)對(duì)外提供的await函數(shù)在底層都是調(diào)用該了doawait函數(shù),
其源代碼如下:
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// 保存當(dāng)前鎖
final ReentrantLock lock = this.lock;
// 鎖定
lock.lock();
try {
// 保存當(dāng)前代
final Generation g = generation;
if (g.broken) // 屏障被破壞,拋出異常
throw new BrokenBarrierException();
if (Thread.interrupted()) { // 線(xiàn)程被中斷
// 損壞當(dāng)前屏障,并且喚醒所有的線(xiàn)程,只有擁有鎖的時(shí)候才會(huì)調(diào)用
breakBarrier();
// 拋出異常
throw new InterruptedException();
}
// 減少正在等待進(jìn)入屏障的線(xiàn)程數(shù)量
int index = --count;
if (index == 0) { // 正在等待進(jìn)入屏障的線(xiàn)程數(shù)量為0,所有線(xiàn)程都已經(jīng)進(jìn)入
// 運(yùn)行的動(dòng)作標(biāo)識(shí)
boolean ranAction = false;
try {
// 保存運(yùn)行動(dòng)作
final Runnable command = barrierCommand;
if (command != null) // 動(dòng)作不為空
// 運(yùn)行
command.run();
// 設(shè)置ranAction狀態(tài)
ranAction = true;
// 進(jìn)入下一代
nextGeneration();
return 0;
} finally {
if (!ranAction) // 沒(méi)有運(yùn)行的動(dòng)作
// 損壞當(dāng)前屏障
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
// 無(wú)限循環(huán)
for (;;) {
try {
if (!timed) // 沒(méi)有設(shè)置等待時(shí)間
// 等待
trip.await();
else if (nanos > 0L) // 設(shè)置了等待時(shí)間,并且等待時(shí)間大于0
// 等待指定時(shí)長(zhǎng)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) { // 等于當(dāng)前代并且屏障沒(méi)有被損壞
// 損壞當(dāng)前屏障
breakBarrier();
// 拋出異常
throw ie;
} else { // 不等于當(dāng)前帶后者是屏障被損壞
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
// 中斷當(dāng)前線(xiàn)程
Thread.currentThread().interrupt();
}
}
if (g.broken) // 屏障被損壞,拋出異常
throw new BrokenBarrierException();
if (g != generation) // 不等于當(dāng)前代
// 返回索引
return index;
if (timed && nanos <= 0L) { // 設(shè)置了等待時(shí)間,并且等待時(shí)間小于0
// 損壞屏障
breakBarrier();
// 拋出異常
throw new TimeoutException();
}
}
} finally {
// 釋放鎖
lock.unlock();
}
}核心函數(shù) - nextGeneration函數(shù)
此函數(shù)在所有線(xiàn)程進(jìn)入屏障后會(huì)被調(diào)用,即生成下一個(gè)版本,所有線(xiàn)程又可以重新進(jìn)入到屏障中,
其源代碼如下:
private void nextGeneration() {
// signal completion of last generation
// 喚醒所有線(xiàn)程
trip.signalAll();
// set up next generation
// 恢復(fù)正在等待進(jìn)入屏障的線(xiàn)程數(shù)量
count = parties;
// 新生一代
generation = new Generation();
}在此函數(shù)中會(huì)調(diào)用AQS的signalAll方法,即喚醒所有等待線(xiàn)程。如果所有的線(xiàn)程都在等待此條件,則喚醒所有線(xiàn)程。
其源代碼如:
public final void signalAll() {
if (!isHeldExclusively()) // 不被當(dāng)前線(xiàn)程獨(dú)占,拋出異常
throw new IllegalMonitorStateException();
// 保存condition隊(duì)列頭節(jié)點(diǎn)
Node first = firstWaiter;
if (first != null) // 頭節(jié)點(diǎn)不為空
// 喚醒所有等待線(xiàn)程
doSignalAll(first);
}到此這篇關(guān)于Java中的 CyclicBarrier詳解的文章就介紹到這了,更多相關(guān)Java中的 CyclicBarrier內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java注冊(cè)郵箱激活驗(yàn)證實(shí)現(xiàn)代碼
這篇文章主要介紹了Java注冊(cè)郵箱激活驗(yàn)證實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2013-12-12
java實(shí)現(xiàn)下載文件到默認(rèn)瀏覽器路徑
這篇文章主要介紹了java實(shí)現(xiàn)下載文件到默認(rèn)瀏覽器路徑,具有很好的參考價(jià)值,希望對(duì)的大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Springboot使用MybatisPlus實(shí)現(xiàn)mysql樂(lè)觀鎖
MySQL中的樂(lè)觀鎖(Optimistic?Locking)是一種并發(fā)控制策略,本文將使用Springboot和MybatisPlus實(shí)現(xiàn)MySQL中的樂(lè)觀鎖,需要的可以參考下2024-12-12
使用arthas命令redefine實(shí)現(xiàn)Java熱更新(推薦)
今天分享一個(gè)非常重要的命令 redefine ,主要作用是加載外部的 .class 文件,用來(lái)替換 JVM 已經(jīng)加載的類(lèi),總結(jié)起來(lái)就是實(shí)現(xiàn)了 Java 的熱更新,感興趣的朋友跟隨小編一起看看吧2020-05-05
java.net.ConnectException: Connection refused問(wèn)題解決辦法
這篇文章主要介紹了java.net.ConnectException: Connection refused問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下2016-12-12
Java使用JDBC連接Oracle_MSSQL實(shí)例代碼
這篇文章主要介紹了Java使用JDBC連接Oracle_MSSQL實(shí)例代碼,需要的朋友可以參考下2014-01-01
Java應(yīng)用多機(jī)器部署解決大量定時(shí)任務(wù)問(wèn)題
這篇文章主要介紹了Java應(yīng)用多機(jī)器部署解決大量定時(shí)任務(wù)問(wèn)題,兩臺(tái)服務(wù)器同時(shí)部署了同一套代碼, 代碼中寫(xiě)有spring自帶的定時(shí)任務(wù),但是每次執(zhí)行定時(shí)任務(wù)時(shí)只需要一臺(tái)機(jī)器去執(zhí)行,需要的朋友可以參考下2019-07-07
java實(shí)體類(lèi)轉(zhuǎn)成map的實(shí)現(xiàn)
這篇文章主要介紹了java實(shí)體類(lèi)轉(zhuǎn)成map的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06

