一文搞懂四種同步工具類
來源:juejin.cn/post/6844903958360621064
CountDownLatch
解釋:
代碼:
public?class?TestCountDownLatch?{
????public?static?void?main(String[]?args)?{
????????//?需要等待兩個(gè)線程,所以傳入?yún)?shù)為2
????????CountDownLatch?latch?=?new?CountDownLatch(2);
????????//?該線程運(yùn)行1秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(1000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????//?該線程運(yùn)行3秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(3000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????try?{
????????????System.out.println("請(qǐng)1號(hào)選手和2號(hào)選手各就各位!");
????????????//?主線程在此等待兩個(gè)線程執(zhí)行完畢之后繼續(xù)執(zhí)行
????????????latch.await();
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//?兩個(gè)線程執(zhí)行完畢后,主線程恢復(fù)運(yùn)行
????????System.out.println("裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!");
????}
}
運(yùn)行結(jié)果:
請(qǐng)1號(hào)選手和2號(hào)選手各就各位!
1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!
2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!
裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!
如果去掉CountDownLatch的效果呢?運(yùn)行結(jié)果就會(huì)變成如下:
請(qǐng)1號(hào)選手和2號(hào)選手各就各位!
裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!
1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!
2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!
CyclicBarrier
解釋:
我們舉一個(gè)例子,兩個(gè)選手進(jìn)行比賽,一共進(jìn)行三輪比賽。
代碼:
public?class?TestCyclicBarrier?{
????//?1號(hào)選手跑的輪數(shù)
????public?static?int?countA?=?1;
????//?2號(hào)選手跑的輪數(shù)
????public?static?int?countB?=?1;
????public?static?void?main(String[]?args)?{
????????//?填入2,代表2個(gè)線程互相等待
????????CyclicBarrier?barrier?=?new?CyclicBarrier(2);
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//?一共跑三輪
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????System.out.println("1號(hào)選手開始跑!當(dāng)前第"?+?countA++?+?"輪比賽!");
????????????????????//?1號(hào)選手跑得慢,每次跑三秒
????????????????????try?{
????????????????????????Thread.sleep(3000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("1號(hào)選手抵達(dá)終點(diǎn)!");
????????????????????????//?調(diào)用等待方法,在此等待其他選手
????????????????????????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號(hào)選手開始跑!當(dāng)前第"?+?countB++?+?"輪比賽!");
????????????????????try?{
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("2號(hào)選手抵達(dá)終點(diǎn)!");
????????????????????????//?調(diào)用等待方法,在此等待其他選手
????????????????????????barrier.await();
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}?catch?(BrokenBarrierException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????}
}
運(yùn)行結(jié)果:
1號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第3輪比賽!
2號(hào)選手開始跑!當(dāng)前第3輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
每輪比賽1號(hào)選手和2號(hào)選手都會(huì)回到起跑線互相等待,再開啟下一輪比賽。
搜索公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師后臺(tái)回復(fù)“2T”,獲取一份驚喜禮包。
如果不加CyclicBarrier呢?
1號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
2號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
2號(hào)選手開始跑!當(dāng)前第3輪比賽!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第3輪比賽!
1號(hào)選手抵達(dá)終點(diǎn)!
此時(shí)2號(hào)選手就直接跑完三輪比賽,不等1號(hào)選手了。
Semaphore
Semaphore英文的字面意思是信號(hào)量。它的工作機(jī)制是每個(gè)線程想要獲取運(yùn)行的機(jī)會(huì)的話,都必須獲取到信號(hào)量。acquire()方法阻塞的獲取信號(hào)量,release()釋放信號(hào)量。
舉個(gè)例子,假設(shè)我們?nèi)サ鲜磕嵊瓮妫堑鲜磕釗?dān)心游客很多的話,影響大家的游玩體驗(yàn),于是規(guī)定每個(gè)小時(shí)只能賣出兩張門票。這樣就可以控制在游樂園當(dāng)中的游客數(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("顧客拿到門票入場(chǎng)!");
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????try?{
????????????????????????//?等待一小時(shí)再發(fā)門票
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????//?一次性發(fā)出兩張門票
????????????????????System.out.println("售票處第"?+?(i?+?1)?+?"小時(shí)售出兩張票!");
????????????????????semaphore.release();
????????????????????semaphore.release();
????????????????}
????????????}
????????}).start();
????????System.out.println("售票處開始售票!");
????}
}
運(yùn)行結(jié)果:
顧客在售票處等候中...
售票處開始售票!
售票處第1小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!
售票處第2小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!
售票處第3小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!
Exchanger
解釋:
舉個(gè)例子好比以前玩網(wǎng)游的時(shí)候,買家和賣家必須走到地圖上同一地點(diǎn)面對(duì)面進(jìn)行交易一樣,一手交錢一手交裝備。
代碼:
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("賣家到達(dá)地圖上交易地點(diǎn)");
????????????????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("買家到達(dá)地圖上交易地點(diǎn)");
????????????????try?{
????????????????????System.out.println("我是買家,換回了"?+?exchanger.exchange(money));
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}).start();
????}
我是賣家,我?guī)еb備過來了!
我是買家,我?guī)е蝗f游戲幣過來了
賣家達(dá)到交易地點(diǎn)
買家到達(dá)交易地點(diǎn)
我是買家,換回了裝備
我是賣家,換回了一萬游戲幣
PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、轉(zhuǎn)發(fā)、在看。
來源:juejin.cn/post/6844903958360621064 CountDownLatch
解釋:
代碼:
public?class?TestCountDownLatch?{
????public?static?void?main(String[]?args)?{
????????//?需要等待兩個(gè)線程,所以傳入?yún)?shù)為2
????????CountDownLatch?latch?=?new?CountDownLatch(2);
????????//?該線程運(yùn)行1秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(1000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????//?該線程運(yùn)行3秒
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????Thread.sleep(3000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println("2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!");
????????????????latch.countDown();
????????????}
????????}).start();
????????
????????try?{
????????????System.out.println("請(qǐng)1號(hào)選手和2號(hào)選手各就各位!");
????????????//?主線程在此等待兩個(gè)線程執(zhí)行完畢之后繼續(xù)執(zhí)行
????????????latch.await();
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//?兩個(gè)線程執(zhí)行完畢后,主線程恢復(fù)運(yùn)行
????????System.out.println("裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!");
????}
}運(yùn)行結(jié)果:
請(qǐng)1號(hào)選手和2號(hào)選手各就各位!
1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!
2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!
裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!如果去掉CountDownLatch的效果呢?運(yùn)行結(jié)果就會(huì)變成如下:
請(qǐng)1號(hào)選手和2號(hào)選手各就各位!
裁判發(fā)槍,1號(hào)選手和2號(hào)選手開跑!
1號(hào)選手準(zhǔn)備就緒!用時(shí)1秒!
2號(hào)選手準(zhǔn)備就緒!用時(shí)3秒!CyclicBarrier
解釋:
我們舉一個(gè)例子,兩個(gè)選手進(jìn)行比賽,一共進(jìn)行三輪比賽。
代碼:
public?class?TestCyclicBarrier?{
????//?1號(hào)選手跑的輪數(shù)
????public?static?int?countA?=?1;
????//?2號(hào)選手跑的輪數(shù)
????public?static?int?countB?=?1;
????public?static?void?main(String[]?args)?{
????????//?填入2,代表2個(gè)線程互相等待
????????CyclicBarrier?barrier?=?new?CyclicBarrier(2);
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//?一共跑三輪
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????System.out.println("1號(hào)選手開始跑!當(dāng)前第"?+?countA++?+?"輪比賽!");
????????????????????//?1號(hào)選手跑得慢,每次跑三秒
????????????????????try?{
????????????????????????Thread.sleep(3000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("1號(hào)選手抵達(dá)終點(diǎn)!");
????????????????????????//?調(diào)用等待方法,在此等待其他選手
????????????????????????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號(hào)選手開始跑!當(dāng)前第"?+?countB++?+?"輪比賽!");
????????????????????try?{
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????try?{
????????????????????????System.out.println("2號(hào)選手抵達(dá)終點(diǎn)!");
????????????????????????//?調(diào)用等待方法,在此等待其他選手
????????????????????????barrier.await();
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}?catch?(BrokenBarrierException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????}
}運(yùn)行結(jié)果:
1號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第3輪比賽!
2號(hào)選手開始跑!當(dāng)前第3輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!每輪比賽1號(hào)選手和2號(hào)選手都會(huì)回到起跑線互相等待,再開啟下一輪比賽。
搜索公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師后臺(tái)回復(fù)“2T”,獲取一份驚喜禮包。
如果不加CyclicBarrier呢?
1號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手開始跑!當(dāng)前第1輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
2號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
2號(hào)選手開始跑!當(dāng)前第3輪比賽!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第2輪比賽!
2號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手抵達(dá)終點(diǎn)!
1號(hào)選手開始跑!當(dāng)前第3輪比賽!
1號(hào)選手抵達(dá)終點(diǎn)!此時(shí)2號(hào)選手就直接跑完三輪比賽,不等1號(hào)選手了。
Semaphore
Semaphore英文的字面意思是信號(hào)量。它的工作機(jī)制是每個(gè)線程想要獲取運(yùn)行的機(jī)會(huì)的話,都必須獲取到信號(hào)量。acquire()方法阻塞的獲取信號(hào)量,release()釋放信號(hào)量。
舉個(gè)例子,假設(shè)我們?nèi)サ鲜磕嵊瓮妫堑鲜磕釗?dān)心游客很多的話,影響大家的游玩體驗(yàn),于是規(guī)定每個(gè)小時(shí)只能賣出兩張門票。這樣就可以控制在游樂園當(dāng)中的游客數(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("顧客拿到門票入場(chǎng)!");
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????}
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????for?(int?i?=?0;?i?3;?i++)?{
????????????????????try?{
????????????????????????//?等待一小時(shí)再發(fā)門票
????????????????????????Thread.sleep(1000);
????????????????????}?catch?(InterruptedException?e)?{
????????????????????????e.printStackTrace();
????????????????????}
????????????????????//?一次性發(fā)出兩張門票
????????????????????System.out.println("售票處第"?+?(i?+?1)?+?"小時(shí)售出兩張票!");
????????????????????semaphore.release();
????????????????????semaphore.release();
????????????????}
????????????}
????????}).start();
????????System.out.println("售票處開始售票!");
????}
}運(yùn)行結(jié)果:
顧客在售票處等候中...
售票處開始售票!
售票處第1小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!
售票處第2小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!
售票處第3小時(shí)售出兩張票!
顧客拿到門票入場(chǎng)!
顧客拿到門票入場(chǎng)!Exchanger
解釋:
舉個(gè)例子好比以前玩網(wǎng)游的時(shí)候,買家和賣家必須走到地圖上同一地點(diǎn)面對(duì)面進(jìn)行交易一樣,一手交錢一手交裝備。
代碼:
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("賣家到達(dá)地圖上交易地點(diǎn)");
????????????????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("買家到達(dá)地圖上交易地點(diǎn)");
????????????????try?{
????????????????????System.out.println("我是買家,換回了"?+?exchanger.exchange(money));
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}).start();
????}我是賣家,我?guī)еb備過來了!
我是買家,我?guī)е蝗f游戲幣過來了
賣家達(dá)到交易地點(diǎn)
買家到達(dá)交易地點(diǎn)
我是買家,換回了裝備
我是賣家,換回了一萬游戲幣PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、轉(zhuǎn)發(fā)、在看。
評(píng)論
圖片
表情
