CountDownLatch

業(yè)務場景一

業(yè)務場景描述:假設一條流水線上有三個工作者:worker1,worker2颠通,worker3。有一個任務的完成需要他們?nèi)邊f(xié)作完成,worker3可以開始這個任務的前提是worker1和worker2完成了他們的工作僻爽,而worker1和worker2是可以并行他們各自的工作的。

join實現(xiàn)

public class CountDownLatchAndJoin {

    public static void main(String[] args) throws InterruptedException {

        // 三個獨立的工人線程
        worker worker1 = new worker("worker1", (long) (Math.random()*4000));
        worker worker2 = new worker("worker2", (long) (Math.random()*4000));
        worker worker3 = new worker("worker3", (long) (Math.random()*4000));
//        worker worker1 = new worker("worker1", 6000);
//        worker worker2 = new worker("worker2", 5000);
//        worker worker3 = new worker("worker3", 5000);
        worker1.start();
        worker2.start();
        
        worker1.join();
        worker2.join();
        System.out.println("準備工作就緒...");

        worker3.start();

    }

    // 工人類
    public static class worker extends Thread {
        // 名字
        private String name;
        //工作時間
        private long time;

        worker(String name, long time) {
            this.name = name;
            this.time = time;
        }

        public void run() {
            try {
                System.out.println(name + "開始工作");
                Thread.sleep(time);
                System.out.println(name + "工作完成贾惦,耗費時間=" + time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

結果:

worker2開始工作
worker1開始工作
worker1工作完成胸梆,耗費時間=601
worker2工作完成敦捧,耗費時間=2886
準備工作就緒...
worker3開始工作
worker3工作完成,耗費時間=686

可以順利的完成工作碰镜,join的工作原理是兢卵,不停檢查thread是否存活,如果存活則讓當前線程永遠wait绪颖,直到thread線程終止秽荤,線程的notifyAll就會被調(diào)用,還可以理解為join就是插隊的意思


CountDownLatch實現(xiàn)

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        // 初始化計數(shù)器為2
        CountDownLatch countDownLatch = new CountDownLatch(2);

        // 三個獨立的工人線程
        worker worker1 = new worker("worker1", (long) (Math.random() * 4000), countDownLatch);
        worker worker2 = new worker("worker2", (long) (Math.random() * 4000), countDownLatch);
        worker worker3 = new worker("worker3", (long) (Math.random() * 4000), countDownLatch);
        worker1.start();
        worker2.start();

        // 當計數(shù)器不為0的時候均等待
        countDownLatch.await();

        System.out.println("準備工作就緒...");
        worker3.start();
    }

    public static class worker extends Thread {

        private String name;
        private long time;
        private CountDownLatch countDownLatch;

        worker(String name, long time, CountDownLatch countDownLatch) {
            this.name = name;
            this.time = time;
            this.countDownLatch = countDownLatch;
        }

        public void run() {
            System.out.println(name + " 開始工作了菠发。王滤。。");
            // 減一
            countDownLatch.countDown();
            System.out.println(name + " 工作完成滓鸠。雁乡。。");
        }
    }
}

創(chuàng)建一個計數(shù)器為2的 CountDownLatch 糜俗,讓Worker持有這個CountDownLatch 實例踱稍,當完成自己的工作后,調(diào)用countDownLatch.countDown() 方法將計數(shù)器減1悠抹。countDownLatch.await() 方法會一直阻塞直到計數(shù)器為0珠月,主線程才會繼續(xù)往下執(zhí)行。

運行結果

worker1 開始工作了楔敌。啤挎。。
worker1 工作完成卵凑。庆聘。。
worker2 開始工作了勺卢。伙判。。
worker2 工作完成黑忱。宴抚。。
準備工作就緒...
worker3 開始工作了甫煞。菇曲。。
worker3 工作完成抚吠。羊娃。。

從結果上來看埃跷,都解決了問題蕊玷,但是下面的場景二邮利?


業(yè)務場景二

只能CountDownLatch實現(xiàn)

業(yè)務場景:假設worker的工作可以分為兩個階段,work3 只需要等待work1和work2完成他們各自工作的第一個階段之后就可以開始自己的工作了垃帅,而不是場景1中的必須等待work1和work2把他們的工作全部完成之后才能開始延届。這樣join就不可以實現(xiàn)了,應當采用CountDownLatch 來實現(xiàn)贸诚。

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        // 初始化計數(shù)器為5
        CountDownLatch countDownLatch = new CountDownLatch(5);

        // 六個獨立的工人線程
        worker worker1 = new worker("worker1", (long) (Math.random() * 4000), countDownLatch);
        worker worker2 = new worker("worker2", (long) (Math.random() * 4000), countDownLatch);
        worker worker3 = new worker("worker3", (long) (Math.random() * 4000), countDownLatch);
        worker worker4 = new worker("worker4", (long) (Math.random() * 4000), countDownLatch);
        worker worker5 = new worker("worker5", (long) (Math.random() * 4000), countDownLatch);
        worker worker6 = new worker("worker6", (long) (Math.random() * 4000), countDownLatch);

        worker1.start();
        worker2.start();
        worker3.start();
        worker4.start();
        worker5.start();

        // 當計數(shù)器不為0的時候均等待
        countDownLatch.await();

        System.out.println("準備工作就緒...");
        worker6.start();
    }

    public static class worker extends Thread {

        private String name;
        private long time;
        private CountDownLatch countDownLatch;

        worker(String name, long time, CountDownLatch countDownLatch) {
            this.name = name;
            this.time = time;
            this.countDownLatch = countDownLatch;
        }

        public void run() {
            try {
                System.out.println(name + " 工作開始方庭。。酱固。");
                Thread.sleep(time);
                System.out.println(name + " 第一階段工作完成械念。。运悲。用時:" + time);
                // 計數(shù)器減一
                countDownLatch.countDown();
                // 假設第二階段的工作都需要兩秒完成
                Thread.sleep(2000);
                System.out.println(name + " 第二階段工作完成龄减。。班眯。用時:" + (time + 2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

多運行幾次發(fā)現(xiàn):線程6等到前面5個線程的第一階段全部完成希停,就開始運行了,運行結果:

worker3 工作開始署隘。宠能。。
worker2 工作開始磁餐。违崇。。
worker1 工作開始诊霹。羞延。。
worker4 工作開始畅哑。肴楷。水由。
worker5 工作開始荠呐。。砂客。
worker3 第一階段工作完成泥张。。鞠值。用時:1410
worker5 第一階段工作完成媚创。。彤恶。用時:2022
worker2 第一階段工作完成钞钙。鳄橘。。用時:2273
worker1 第一階段工作完成芒炼。瘫怜。。用時:2856
worker3 第二階段工作完成本刽。鲸湃。。用時:3410
worker4 第一階段工作完成子寓。暗挑。。用時:3430
準備工作就緒...
worker6 工作開始斜友。炸裆。。
worker5 第二階段工作完成蝙寨。晒衩。。用時:4022
worker2 第二階段工作完成墙歪。听系。。用時:4273
worker1 第二階段工作完成虹菲。靠胜。。用時:4856
worker4 第二階段工作完成毕源。浪漠。。用時:5430
worker6 第一階段工作完成霎褐。址愿。。用時:3773
worker6 第二階段工作完成冻璃。响谓。。用時:5773

總結:

  • 調(diào)用thread.join() 方法必須等thread 執(zhí)行完畢省艳,當前線程才能繼續(xù)往下執(zhí)行娘纷,而CountDownLatch通過計數(shù)器提供了更靈活的控制,只要檢測到計數(shù)器為0當前線程就可以往下執(zhí)行而不用管相應的thread是否執(zhí)行完畢跋炕。
  • CountDownLatch底層基于AQS赖晶。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辐烂,隨后出現(xiàn)的幾起案子遏插,更是在濱河造成了極大的恐慌捂贿,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胳嘲,死亡現(xiàn)場離奇詭異眷蜓,居然都是意外死亡,警方通過查閱死者的電腦和手機胎围,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門吁系,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人白魂,你說我怎么就攤上這事汽纤。” “怎么了福荸?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵蕴坪,是天一觀的道長。 經(jīng)常有香客問我敬锐,道長背传,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任台夺,我火速辦了婚禮径玖,結果婚禮上,老公的妹妹穿的比我還像新娘颤介。我一直安慰自己梳星,他們只是感情好,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布滚朵。 她就那樣靜靜地躺著冤灾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辕近。 梳的紋絲不亂的頭發(fā)上韵吨,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音移宅,去河邊找鬼归粉。 笑死,一個胖子當著我的面吹牛吞杭,可吹牛的內(nèi)容都是我干的盏浇。 我是一名探鬼主播变丧,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼芽狗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痒蓬?” 一聲冷哼從身側(cè)響起童擎,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤滴劲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后顾复,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體班挖,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年芯砸,在試婚紗的時候發(fā)現(xiàn)自己被綠了萧芙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡假丧,死狀恐怖双揪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情包帚,我是刑警寧澤渔期,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站渴邦,受9級特大地震影響疯趟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谋梭,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一信峻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓮床,春花似錦站欺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至峭沦,卻和暖如春贾虽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吼鱼。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工蓬豁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人菇肃。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓地粪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親琐谤。 傳聞我的和親對象是個殘疾皇子蟆技,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351