一文搞懂四種同步工具類
來源:juejin.cn/post/6844903958360621064
CountDownLatch
解釋:
代碼:
public?class?TestCountDownLatch?{
????public?static?void?main(String[]?args)?{
????????//?需要等待兩個線程,所以傳入參數(shù)為2
????????CountDownLatch?latch?=?new?CountDownLatch(2);
????????//?該線程運行1秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(1000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("1號選手準備就緒!用時1秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????//?該線程運行3秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(3000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("2號選手準備就緒!用時3秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????try?{
????????????System.out.println("請1號選手和2號選手各就各位!");
????????????//?主線程在此等待兩個線程執(zhí)行完畢之后繼續(xù)執(zhí)行
????????????latch.await();
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//?兩個線程執(zhí)行完畢后,主線程恢復運行
????????System.out.println("裁判發(fā)槍,1號選手和2號選手開跑!");
????}
}
運行結果:
請1號選手和2號選手各就各位!
1號選手準備就緒!用時1秒!
2號選手準備就緒!用時3秒!
裁判發(fā)槍,1號選手和2號選手開跑!
如果去掉CountDownLatch的效果呢?運行結果就會變成如下:
請1號選手和2號選手各就各位!
裁判發(fā)槍,1號選手和2號選手開跑!
1號選手準備就緒!用時1秒!
2號選手準備就緒!用時3秒!
CyclicBarrier
解釋:
我們舉一個例子,兩個選手進行比賽,一共進行三輪比賽。
代碼:
public?class?TestCyclicBarrier?{
????//?1號選手跑的輪數(shù)
????public?static?int?countA?=?1;
????//?2號選手跑的輪數(shù)
????public?static?int?countB?=?1;
????public?static?void?main(String[]?args)?{
????????//?填入2,代表2個線程互相等待
????????CyclicBarrier?barrier?=?new?CyclicBarrier(2);
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//?一共跑三輪
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????System.out.println("1號選手開始跑!當前第"?+?countA++?+?"輪比賽!");
????????????????????//?1號選手跑得慢,每次跑三秒
????????????????????try?{
????????????????????????Thread.sleep(3000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("1號選手抵達終點!");
????????????????????????//?調用等待方法,在此等待其他選手
????????????????????????barrier.await();
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}?catch?(BrokenBarrierException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//?一共等待三輪
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????System.out.println("2號選手開始跑!當前第"?+?countB++?+?"輪比賽!");
????????????????????try?{
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("2號選手抵達終點!");
????????????????????????//?調用等待方法,在此等待其他選手
????????????????????????barrier.await();
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}?catch?(BrokenBarrierException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????}
}
運行結果:
1號選手開始跑!當前第1輪比賽!
2號選手開始跑!當前第1輪比賽!
2號選手抵達終點!
1號選手抵達終點!
1號選手開始跑!當前第2輪比賽!
2號選手開始跑!當前第2輪比賽!
2號選手抵達終點!
1號選手抵達終點!
1號選手開始跑!當前第3輪比賽!
2號選手開始跑!當前第3輪比賽!
2號選手抵達終點!
1號選手抵達終點!
每輪比賽1號選手和2號選手都會回到起跑線互相等待,再開啟下一輪比賽。
搜索公眾號互聯(lián)網架構師后臺回復“2T”,獲取一份驚喜禮包。
如果不加CyclicBarrier呢?
1號選手開始跑!當前第1輪比賽!
2號選手開始跑!當前第1輪比賽!
2號選手抵達終點!
2號選手開始跑!當前第2輪比賽!
2號選手抵達終點!
2號選手開始跑!當前第3輪比賽!
1號選手抵達終點!
1號選手開始跑!當前第2輪比賽!
2號選手抵達終點!
1號選手抵達終點!
1號選手開始跑!當前第3輪比賽!
1號選手抵達終點!
此時2號選手就直接跑完三輪比賽,不等1號選手了。
Semaphore
Semaphore英文的字面意思是信號量。它的工作機制是每個線程想要獲取運行的機會的話,都必須獲取到信號量。acquire()方法阻塞的獲取信號量,release()釋放信號量。
舉個例子,假設我們去迪士尼游玩,但是迪士尼擔心游客很多的話,影響大家的游玩體驗,于是規(guī)定每個小時只能賣出兩張門票。這樣就可以控制在游樂園當中的游客數(shù)量了。
代碼:
public?class?TestSemaphore?{
????public?static?void?main(String[]?args)?{
????????Semaphore?semaphore?=?new?Semaphore(0);
????????System.out.println("顧客在售票處等候中");
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????for?(;?;?)?{
????????????????????try?{
????????????????????????Thread.sleep(500);
????????????????????????//?等待出票
????????????????????????semaphore.acquire();
????????????????????????System.out.println("顧客拿到門票入場!");
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????try?{
????????????????????????//?等待一小時再發(fā)門票
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????//?一次性發(fā)出兩張門票
????????????????????System.out.println("售票處第"?+?(i?+?1)?+?"小時售出兩張票!");
????????????????????semaphore.release();
????????????????????semaphore.release();
????????????????}
????????????}
????????}).start();
????????System.out.println("售票處開始售票!");
????}
}
運行結果:
顧客在售票處等候中...
售票處開始售票!
售票處第1小時售出兩張票!
顧客拿到門票入場!
顧客拿到門票入場!
售票處第2小時售出兩張票!
顧客拿到門票入場!
顧客拿到門票入場!
售票處第3小時售出兩張票!
顧客拿到門票入場!
顧客拿到門票入場!
Exchanger
解釋:
Exchanger提供了讓兩個線程互相交換數(shù)據的同步點。Exchanger有點像2個線程的CyclicBarrier,線程之間都是互相等待,區(qū)別在于Exchanger多了交換的操作。
舉個例子好比以前玩網游的時候,買家和賣家必須走到地圖上同一地點面對面進行交易一樣,一手交錢一手交裝備。
代碼:
public?class?TestExchanger?{
????public?static?void?main(String[]?args)?{
????????Exchanger?exchanger?=?new?Exchanger<>();
????????
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????String?weapon?=?"裝備";
????????????????System.out.println("我是賣家,我?guī)е??+?weapon?+?"過來了!");
????????????????try?{
????????????????????Thread.sleep(2000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("賣家到達地圖上交易地點");
????????????????try?{
????????????????????System.out.println("我是賣家,換回了"?+?exchanger.exchange(weapon));
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????String?money?=?"一萬游戲幣";
????????????????System.out.println("我是買家,我?guī)е??+?money?+?"過來了");
????????????????try?{
????????????????????Thread.sleep(4000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("買家到達地圖上交易地點");
????????????????try?{
????????????????????System.out.println("我是買家,換回了"?+?exchanger.exchange(money));
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}).start();
????}
我是賣家,我?guī)еb備過來了!
我是買家,我?guī)е蝗f游戲幣過來了
賣家達到交易地點
買家到達交易地點
我是買家,換回了裝備
我是賣家,換回了一萬游戲幣
感謝您的閱讀,也歡迎您發(fā)表關于這篇文章的任何建議,關注我,技術不迷茫!小編到你上高速。
正文結束
1.不認命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵志故事
5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結果懵了...

評論
圖片
表情
