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