Java中CyclicBarrier的理解與應(yīng)用詳解
一、概述
CyclicBarrier類是JUC框架中的工具類,也是一個同步輔助裝置:允許多個線程去等待直到全部線程抵達了公共的柵欄點。
它的一個很明顯的特點就是Cyclic 循環(huán),也就是說柵欄是可以循環(huán)使用的,激活循環(huán)使用的條件是當(dāng)所有線程通過了柵欄并釋放。
二、源碼分析
//靜態(tài)內(nèi)部類,用于表示屏障的狀態(tài)
private static class Generation {
boolean broken = false;
}
//重入鎖,用于并發(fā)場景下的加鎖和釋放鎖
private final ReentrantLock lock = new ReentrantLock();
//通過重入鎖拿到條件對象,調(diào)用await方法會進入到條件隊列中
private final Condition trip = lock.newCondition();
//表示線程數(shù),可以立即為這些線程數(shù)都執(zhí)行完后,屏障才會打破進入下一代
private final int parties;
//這個是屏障被打破后,執(zhí)行的一個任務(wù)
private final Runnable barrierCommand;
//內(nèi)部內(nèi)實例,存儲屏障狀態(tài)
private Generation generation = new Generation();
//等待執(zhí)行的線程數(shù)
private int count;
//進入下一代,其實就是下一個新的循環(huán),觸發(fā)條件是所有的線程都執(zhí)行完,屏障被打破時
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
//打破屏障,喚醒條件隊列中線程
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
==================================================== 核心方法 =================================================================
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
//上鎖
lock.lock();
try {
final Generation g = generation;
//判斷屏障的狀態(tài)
if (g.broken)
throw new BrokenBarrierException();
//判斷線程是否被打斷
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
//被執(zhí)行的線程數(shù)減一
int index = --count;
//如果當(dāng)前的線程都執(zhí)行完畢
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
//執(zhí)行墊底的barrierCommand方法
command.run();
ranAction = true;
//開始下一個循環(huán),其實也就是重置一下屏障的狀態(tài),將parties的值重新復(fù)制給count并喚醒在條件隊列中的線程
nextGeneration();
return 0;
} finally {
if (!ranAction)
//打破屏障
breakBarrier();
}
}
//無限循環(huán)
for (;;) {
try {
if (!timed)
//調(diào)用await方法等待,其實就是到了條件隊列condition中去了,等待被喚醒
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();
}
}
===================================================================================================================================
//構(gòu)造函數(shù),傳入線程數(shù)和執(zhí)行的方法
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);
}
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//重置count,其實就是開啟一個新的循環(huán)
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}三、練習(xí)
public class MyThread extends Thread{
private String name;
private CyclicBarrier cb;
public MyThread(String name,CyclicBarrier cb){
this.name = name;
this.cb = cb;
}
@Override
public void run() {
try{
System.out.println(Thread.currentThread().getName()+"開始執(zhí)行");
cb.await();
}catch(Exception e){
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"繼續(xù)");
}
}
}
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("屏障被打破,重新開始==========");
}
});
MyThread t1 = new MyThread("t1",cb);
MyThread t2 = new MyThread("t2",cb);
t1.start();
t2.start();
cb.await();
}四、總結(jié)
1、CyclicBarrier和CountDownLatch極為類似,兩者都是柵欄工具類,不同的是,CyclicBarrier可以循環(huán)使用柵欄,而CountDownLatch只能使用一次。兩者都是減法計數(shù),但是數(shù)值的存儲屬性卻不相同,CyclicBarrier使用的是自己的私有屬性parties,而CountDownLatch使用的是AQS類的state屬性。
2、CyclicBarrier和CountDownLatch還有一個不同點在于:CyclicBarrier在所有線程執(zhí)行完后,屏障被打破時,會執(zhí)行barrierCommand最終任務(wù),當(dāng)然不是必須的。
3、在何時使用CountDownLatch和CountDownLatch,還是有稍微差異:CyclicBarrier適合那種跨欄比賽,但是要求所有參賽選手跨過同一個欄后才能跨下一個欄。CountDownLatch適合那種游戲,選手都準(zhǔn)備好了,才能開始游戲主線程。 其實說來說去,無非就是CountDownLatch適合循環(huán)的場景,CountDownLatch適合一次性的場景!
到此這篇關(guān)于Java中CyclicBarrier的理解與應(yīng)用詳解的文章就介紹到這了,更多相關(guān)CyclicBarrier的理解與應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot集成IJPay實現(xiàn)微信v3支付的示例代碼
本文主要介紹了SpringBoot集成IJPay實現(xiàn)微信v3支付的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
新版idea創(chuàng)建spring boot項目的詳細(xì)教程
這篇文章給大家介紹了新版idea創(chuàng)建spring boot項目的詳細(xì)教程,本教程對新手小白友好,若根據(jù)教程創(chuàng)建出現(xiàn)問題導(dǎo)致失敗可下載我提供的源碼,在文章最后,本教程較新,文中通過圖文給大家介紹的非常詳細(xì),感興趣的朋友可以參考下2024-01-01
java小知識之查詢數(shù)據(jù)庫數(shù)據(jù)的元信息
這篇文章主要給大家介紹了關(guān)于java小知識之查詢數(shù)據(jù)庫數(shù)據(jù)的元信息,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2021-10-10
Springboot讀取外部配置文件,項目部署時配置讀取不到問題及解決
這篇文章主要介紹了Springboot讀取外部配置文件,項目部署時配置讀取不到問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06
淺談Spring Cloud中的API網(wǎng)關(guān)服務(wù)Zuul
這篇文章主要介紹了淺談Spring Cloud中的API網(wǎng)關(guān)服務(wù)Zuul,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
淺談Java高并發(fā)解決方案以及高負(fù)載優(yōu)化方法
這篇文章主要介紹了淺談Java高并發(fā)解決方案以及高負(fù)載優(yōu)化方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

