java并發(fā)編程之CountDownLatch,CyclicBarrier笆包,Semaphore的簡單應(yīng)用

前言

這三個(gè)類都是在java1.5的時(shí)候由Doug Lea大神添加于java.util.concurrent环揽,這三個(gè)輔助類都基于AQS同步器框架實(shí)現(xiàn),下面我們簡單介紹下它們的簡單使用

CountDownLatch

CountDownLatch類似是一個(gè)計(jì)數(shù)器庵佣,他可以實(shí)現(xiàn)需要所有任務(wù)都執(zhí)行完畢才可以執(zhí)行接下來的任務(wù)歉胶,日常場(chǎng)景中我們可以使用他來做并行分布運(yùn)算,借用多核cpu對(duì)數(shù)據(jù)分別進(jìn)行計(jì)算巴粪,然后再匯總通今,也可以實(shí)現(xiàn)在加載某些東西前初始化一些信息粥谬。

主要方法

public CountDownLatch(int count);//構(gòu)造函數(shù)
public void countDown()辫塌;//計(jì)數(shù)器-1
public void await() throws InterruptedException漏策;//掛起
public boolean await(long timeout, TimeUnit unit);//與await()類似,這里可以指定時(shí)間臼氨,達(dá)到時(shí)間如果計(jì)數(shù)器沒歸0也可以執(zhí)行下面的東西

簡單例子

private static void countDownLatchApply() throws Exception {
        //初始化2個(gè)
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            try {
                System.out.println("我是線程" + Thread.currentThread().getName() + "我執(zhí)行在"
                        +LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
                //模擬處理耗時(shí)
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }).start();

        new Thread(() -> {
            try {
                System.out.println("我是線程" + Thread.currentThread().getName() + "我執(zhí)行在"+
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
                //模擬處理耗時(shí)
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }).start();


        countDownLatch.await();

        new Thread(() -> {
            System.out.println("我是線程" + Thread.currentThread().getName() + "我需要前面兩個(gè)執(zhí)行完我才可以執(zhí)行掺喻,我執(zhí)行在"+
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
        }).start();

    }

執(zhí)行結(jié)果

我是線程Thread-1我執(zhí)行在2019/05/15 08:05:36
我是線程Thread-0我執(zhí)行在2019/05/15 08:05:36
我是線程Thread-2我需要前面兩個(gè)執(zhí)行完我才可以執(zhí)行,我執(zhí)行在2019/05/15 08:05:38

我們會(huì)看到線程2是需要在線程0和1執(zhí)行玩后再執(zhí)行的储矩,我特意讓線程休眠了2秒感耙,后面的時(shí)間也印證了線程2是在線程0和線程1后2秒執(zhí)行的

CyclicBarrier

回環(huán)柵欄,他可以使線程全部到達(dá)一個(gè)同步點(diǎn)后持隧,再一起執(zhí)行下面的動(dòng)作抑月,他是可重用的,等線程到達(dá)同步點(diǎn)舆蝴,這個(gè)線程是可以被做其他使用的洁仗,我們姑且叫這個(gè)狀態(tài)為可重用態(tài),當(dāng)調(diào)用await(),線程就為可重用態(tài)

主要方法

public CyclicBarrier(int parties);//構(gòu)造方法
public CyclicBarrier(int parties, Runnable barrierAction);//構(gòu)造方法,可實(shí)現(xiàn)更復(fù)雜的動(dòng)作
public int await() throws InterruptedException, BrokenBarrierException;//掛起
public int await(long timeout, TimeUnit unit);//帶時(shí)間,到期可執(zhí)行下面操作

簡單例子

 private static void cyclicBarrierApply() {

        CyclicBarrier cyclicBarrier=new CyclicBarrier(4, new Runnable() {
            @Override
            public void run() {
                System.out.println("我是線程"+Thread.currentThread().getName()+",老板,我按照你的要求在他們向你匯報(bào)前檢查了他們4個(gè)的工作伞访,他們一會(huì)會(huì)親自向你匯報(bào)");
            }
        });

        for (int i = 0; i <4 ; i++) {
            new Thread(() ->{
                try {
                    Thread.sleep(2000L);
                    System.out.println("我是線程"+Thread.currentThread().getName()+",我的工作做完了,等其他線程工作好"
                    +"袜爪,我們一起去向老板匯報(bào)");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    System.out.println("老板豁延,我來向你匯報(bào)工作了");
                }

            }).start();
        }

    }

執(zhí)行結(jié)果

我是線程Thread-0,我的工作做完了,等其他線程工作好,我們一起去向老板匯報(bào)
我是線程Thread-1,我的工作做完了,等其他線程工作好湾蔓,我們一起去向老板匯報(bào)
我是線程Thread-3,我的工作做完了咸包,等其他線程工作好烂瘫,我們一起去向老板匯報(bào)
我是線程Thread-2,我的工作做完了,等其他線程工作好怜校,我們一起去向老板匯報(bào)
我是線程Thread-2,老板,我按照你的要求在他們向你匯報(bào)前檢查了他們4個(gè)的工作,他們一會(huì)會(huì)親自向你匯報(bào)
我是線程Thread-2老板键科,我來向你匯報(bào)工作了
我是線程Thread-3老板,我來向你匯報(bào)工作了
我是線程Thread-1老板漩怎,我來向你匯報(bào)工作了
我是線程Thread-0老板勋颖,我來向你匯報(bào)工作了

我們可以看到所有線程最開始都在完成自己的工作,并等待其他線程一起向“老板”匯報(bào)勋锤,線程完成工作了饭玲,變?yōu)榱丝芍赜脩B(tài),這個(gè)時(shí)候線程2被重用叁执,他被“老板”安排在四個(gè)線程匯報(bào)工作前先檢查他們的工作茄厘,也就是第二個(gè)構(gòu)造方法的運(yùn)用,最后四個(gè)線程一起去向“老板”匯報(bào)工作谈宛。

CountDownLatch與CyclicBarrier的比較

他們的功能有一些類似次哈,CountDownLatch是所有線程都到達(dá)一個(gè)點(diǎn)才能執(zhí)行下面的動(dòng)作,而CyclicBarrier是所有線程都到達(dá)一個(gè)點(diǎn)再一起執(zhí)行下面的動(dòng)作,CountDownLatch不可被重用,CyclicBarrier可以被重用

Semaphore

信號(hào)量泡徙,它可用于對(duì)資源進(jìn)行有效的控制该肴,獲取到許可就可以使用,使用完許可主動(dòng)釋放掉障陶,獲取不到就需要等到有許可可以使用

主要方法

public Semaphore(int permits) //參數(shù)表示許可數(shù)目滋恬,同時(shí)可以允許多少線程進(jìn)行訪問
public Semaphore(int permits, boolean fair)  //fair表示是否是公平的,等待時(shí)間越久的越先獲得許可
public void acquire() throws InterruptedException ;    //獲取一個(gè)許可 會(huì)造成阻塞
public void acquire(int permits) throws InterruptedException ;    //獲取permits個(gè)許可 會(huì)造成阻塞
public void release() ;        //釋放一個(gè)許可 會(huì)造成阻塞
public void release(int permits) ;   //釋放permits個(gè)許可 會(huì)造成阻塞
//下面四個(gè)方法與上面的一樣抱究,但是下面會(huì)立即獲得結(jié)果恢氯,不會(huì)阻塞,操作失敗就返回false
public boolean tryAcquire();
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
public boolean tryAcquire(int permits)
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)

簡單例子

private static void semaphoreApply() throws Exception {
        //倉庫管理員
        Semaphore semaphore = new Semaphore(4);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    //向倉庫管理員要一把鑰匙
                    semaphore.acquire();
                    System.out.println("我是線程" + Thread.currentThread().getName() + "我成功申請(qǐng)到了一把鑰匙");
                    Thread.sleep(3000L);
                    System.out.println("我是線程" + Thread.currentThread().getName() + "我使用好了鑰匙");
                    //給管理員說我用好了
                    semaphore.release();
                    System.out.println("我是線程" + Thread.currentThread().getName() + "我已經(jīng)將鑰匙還回去了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }

運(yùn)行結(jié)果

我是線程Thread-0我成功申請(qǐng)到了一把鑰匙
我是線程Thread-2我成功申請(qǐng)到了一把鑰匙
我是線程Thread-1我成功申請(qǐng)到了一把鑰匙
我是線程Thread-3我成功申請(qǐng)到了一把鑰匙
我是線程Thread-2我使用好了鑰匙
我是線程Thread-1我使用好了鑰匙
我是線程Thread-4我成功申請(qǐng)到了一把鑰匙
我是線程Thread-6我成功申請(qǐng)到了一把鑰匙
我是線程Thread-0我使用好了鑰匙
我是線程Thread-2我已經(jīng)將鑰匙還回去了
我是線程Thread-1我已經(jīng)將鑰匙還回去了
我是線程Thread-5我成功申請(qǐng)到了一把鑰匙
我是線程Thread-0我已經(jīng)將鑰匙還回去了
我是線程Thread-3我使用好了鑰匙
我是線程Thread-3我已經(jīng)將鑰匙還回去了
我是線程Thread-7我成功申請(qǐng)到了一把鑰匙
我是線程Thread-5我使用好了鑰匙
我是線程Thread-5我已經(jīng)將鑰匙還回去了
我是線程Thread-6我使用好了鑰匙
我是線程Thread-7我使用好了鑰匙
我是線程Thread-9我成功申請(qǐng)到了一把鑰匙
我是線程Thread-4我使用好了鑰匙
我是線程Thread-7我已經(jīng)將鑰匙還回去了
我是線程Thread-6我已經(jīng)將鑰匙還回去了
我是線程Thread-8我成功申請(qǐng)到了一把鑰匙
我是線程Thread-4我已經(jīng)將鑰匙還回去了
我是線程Thread-9我使用好了鑰匙
我是線程Thread-9我已經(jīng)將鑰匙還回去了
我是線程Thread-8我使用好了鑰匙
我是線程Thread-8我已經(jīng)將鑰匙還回去了

我們可以看到鼓寺,最開始只有4個(gè)獲取到了許可勋拟,我在這里將線程休眠3秒,模擬耗時(shí)妈候,在這期間沒有其他線程獲取到許可敢靡,并且同時(shí)也只能有四個(gè)在運(yùn)行,每下一個(gè)獲取到許可都必須是有線程釋放許可,

參考資料:《java編程思想》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苦银,一起剝皮案震驚了整個(gè)濱河市啸胧,隨后出現(xiàn)的幾起案子赶站,更是在濱河造成了極大的恐慌,老刑警劉巖纺念,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贝椿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡陷谱,警方通過查閱死者的電腦和手機(jī)烙博,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叭首,“玉大人习勤,你說我怎么就攤上這事”焊瘢” “怎么了图毕?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長眷唉。 經(jīng)常有香客問我予颤,道長,這世上最難降的妖魔是什么冬阳? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任蛤虐,我火速辦了婚禮,結(jié)果婚禮上肝陪,老公的妹妹穿的比我還像新娘驳庭。我一直安慰自己,他們只是感情好氯窍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布饲常。 她就那樣靜靜地躺著,像睡著了一般狼讨。 火紅的嫁衣襯著肌膚如雪贝淤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天政供,我揣著相機(jī)與錄音播聪,去河邊找鬼。 笑死布隔,一個(gè)胖子當(dāng)著我的面吹牛离陶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衅檀,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼枕磁,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了术吝?” 一聲冷哼從身側(cè)響起计济,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤茸苇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后沦寂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體学密,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年传藏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腻暮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毯侦,死狀恐怖哭靖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侈离,我是刑警寧澤试幽,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站卦碾,受9級(jí)特大地震影響铺坞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洲胖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一济榨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绿映,春花似錦擒滑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卸奉,卻和暖如春钝诚,著一層夾襖步出監(jiān)牢的瞬間颖御,已是汗流浹背榄棵。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留潘拱,地道東北人疹鳄。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像芦岂,于是被迫代替她去往敵國和親瘪弓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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