Java并發(fā)工具類(柵欄CyclicBarrier)

CyclicBarrier適用于這樣的情況:你希望創(chuàng)建一組任務(wù)煌张,它們并行地執(zhí)行工作骏融,然后在下一個(gè)步驟之前等待萌狂,直到所有任務(wù)都完成茫藏。柵欄和閉鎖的關(guān)鍵區(qū)別在于,所有線程必須同時(shí)到達(dá)柵欄位置凉当,才能繼續(xù)執(zhí)行售葡。

閉鎖用于等待事件挟伙,而柵欄是線程之間彼此等待,等到都到的時(shí)候再?zèng)Q定做下一件事贮缅∏垂可以參考Java并發(fā)工具類(閉鎖CountDownLatch)

拿運(yùn)動(dòng)員的事情舉例筷笨,運(yùn)動(dòng)員們跑到終點(diǎn),互相等待所有人都到達(dá)終點(diǎn)后昌跌,再一起去做喝酒這件事照雁。(運(yùn)動(dòng)員也許不能喝酒的饺蚊,也許大家再跑一輪。)

下面用一個(gè)賽馬程序來(lái)舉例:

賽馬
package concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

class Horse implements Runnable {
    private static int counter = 0;
    private final int id = counter++;
    private int strides = 0;
    private static Random rand = new Random(47);
    private static CyclicBarrier barrier;
    public Horse(CyclicBarrier b) {barrier = b;}
    public synchronized int getStrides() {return strides;}
    public void run() {
        try {
            while (!Thread.interrupted()) {  //線程內(nèi)不斷循環(huán)
                synchronized (this) {
                    strides += rand.nextInt(3);   //每次馬可以走0,1或者2步
                }
                barrier.await();  //走完后,就等所有其它馬也走完籍凝,才能開始下一回合
            }
        } catch (InterruptedException e) {

        } catch (BrokenBarrierException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "Horse " + id + " ";
    }

    public String tracks() {
        StringBuilder s =new StringBuilder();
        for(int i = 0; i < getStrides();i++)
            s.append("*");   //這里打印每個(gè)馬走的軌跡
        s.append(id);
        return s.toString();
    }
}
public class HorseRace {
    static final int FINISH_LINE = 75;
    private List<Horse> horses = new ArrayList<Horse>();
    private ExecutorService exec = Executors.newCachedThreadPool();
    private CyclicBarrier barrier;
    public HorseRace(int nHorses, final int pause) {
        barrier = new CyclicBarrier(nHorses, new Runnable() {
            @Override
            public void run() {
                StringBuilder s = new StringBuilder();
                for (int i = 0; i < FINISH_LINE; i++) {
                    s.append("="); //打印賽道
                }
                System.out.println(s);
                for (Horse horse : horses) {
                    System.out.println(horse.tracks());  //打印每匹馬的軌跡
                }
                for (Horse horse : horses) {
                  if (horse.getStrides() >= FINISH_LINE) {
                      System.out.println(horse + "won!");   //每次檢查,如果哪匹馬到終點(diǎn)了退盯,終止所有線程
                      exec.shutdownNow();
                      return;
                  }
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(pause); //每走完一輪泻肯,暫停一小會(huì)輸出
                } catch (InterruptedException e) {
                    System.out.println("barrier-action sleep interrupted");
                }
            }
        });

        for (int i = 0; i < nHorses; i++) {
            Horse horse = new Horse(barrier);
            horses.add(horse);
            exec.execute(horse);  //所有馬的線程開始執(zhí)行
        }
    }

    public static void main(String[] args) {
        int nHorses = 7;
        int pause = 200;
        new HorseRace(nHorses, pause);
    }
}

我們假設(shè)賽道長(zhǎng)為75软免,馬每次能走0,1或者2步膏萧,每次走完一輪后蝌衔,互相等待噩斟。一旦所有馬越過(guò)柵欄驮宴,它就會(huì)自動(dòng)為下一回合的比賽做好準(zhǔn)備齐鲤。讀者可以運(yùn)行我的程序给郊,在控制臺(tái)上可以展示出一定的動(dòng)畫效果捧灰。

上面的例子中毛俏,我們向CyclicBarrier提供一個(gè)“柵欄動(dòng)作”,它是一個(gè)Runnable焕蹄,當(dāng)計(jì)數(shù)值到達(dá)0時(shí)自動(dòng)執(zhí)行擦盾,這是CyclicBarrier和CountDownLatch之間的另一個(gè)區(qū)別淌哟。

public CyclicBarrier(int parties, Runnable barrierAction)

除此之外徒仓,CyclicBarrier還提供其他有用的方法,比如getNumberWaiting方法可以獲得CyclicBarrier阻塞的線程數(shù)量症见。isBroken方法用來(lái)知道阻塞的線程是否被中斷谋作。比如以下代碼執(zhí)行完之后會(huì)返回true乎芳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奈惑,一起剝皮案震驚了整個(gè)濱河市肴甸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌友扰,老刑警劉巖村怪,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異实愚,居然都是意外死亡兼呵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門腊敲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)击喂,“玉大人,你說(shuō)我怎么就攤上這事碰辅《海” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵没宾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我循衰,道長(zhǎng)铲敛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任会钝,我火速辦了婚禮伐蒋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迁酸。我一直安慰自己先鱼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布奸鬓。 她就那樣靜靜地躺著焙畔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪串远。 梳的紋絲不亂的頭發(fā)上宏多,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音抑淫,去河邊找鬼绷落。 笑死,一個(gè)胖子當(dāng)著我的面吹牛始苇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筐喳,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼催式,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼函喉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起荣月,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤管呵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后哺窄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐下,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年萌业,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坷襟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡生年,死狀恐怖婴程,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抱婉,我是刑警寧澤档叔,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蒸绩,受9級(jí)特大地震影響衙四,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜患亿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一届搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窍育,春花似錦卡睦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乞娄,卻和暖如春瞬逊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仪或。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工确镊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人范删。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓蕾域,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旨巷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容