<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文搞懂四種同步工具類

          共 2646字,需瀏覽 6分鐘

           ·

          2021-11-10 02:18


          作者:CoderV的進(jìn)階筆記

          來源:juejin.cn/post/6844903958360621064

          CountDownLatch

          解釋:

          CountDownLatch相當(dāng)于一個(gè)門閂,門閂上掛了N把鎖。只有N把鎖都解開的話,門才會(huì)打開。怎么理解呢?我舉一個(gè)賽跑比賽的例子,賽跑比賽中必須等待所有選手都準(zhǔn)備好了,裁判才能開發(fā)令槍。選手才可以開始跑。

          CountDownLatch當(dāng)中主要有兩個(gè)方法,一個(gè)是await()會(huì)掛上鎖阻塞當(dāng)前線程,相當(dāng)于裁判站在起始點(diǎn)等待,等待各位選手準(zhǔn)備就緒,一個(gè)是countDown方法用于解鎖,相當(dāng)于選手準(zhǔn)備好了之后調(diào)用countDown方法告訴裁判自己準(zhǔn)備就緒,當(dāng)所有人都準(zhǔn)備好了之后裁判開發(fā)令槍。

          代碼:

          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秒!

          裁判就會(huì)在選手還未準(zhǔn)備就緒的時(shí)候開發(fā)令槍,這就亂套了。
          其實(shí)CountDownLatch一個(gè)最簡(jiǎn)單的用處就是計(jì)算多線程執(zhí)行完畢時(shí)的時(shí)間。像剛才的例子當(dāng)中兩個(gè)線程并行執(zhí)行了共花費(fèi)了3秒鐘。

          CyclicBarrier

          解釋:

          CyclicBarrier就像一個(gè)柵欄,將各個(gè)線程攔住。Cyclic是循環(huán)的英文,表明該工具可以進(jìn)行循環(huán)使用。CyclicBarrier(N)的構(gòu)造參數(shù)表明該一共有幾個(gè)線程需要互相等待。它相當(dāng)于N個(gè)選手約定進(jìn)行多次比賽,每次比賽完都要在起跑點(diǎn)互相等待。

          讀者可能會(huì)馬上疑惑這不是和CountDownLatch一樣嗎?不一樣。因?yàn)镃ountDownLatch是裁判等待選手,是調(diào)用await()方法的線程,等待調(diào)用countDown()方法的各個(gè)線程。而CyclicBarrier是選手等待選手,是調(diào)用await()方法的線程互相等待,等待其他線程都運(yùn)行好之后,再開始下一輪運(yùn)行。

          我們舉一個(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

          解釋:

          Exchanger提供了讓兩個(gè)線程互相交換數(shù)據(jù)的同步點(diǎn)。Exchanger有點(diǎn)像2個(gè)線程的CyclicBarrier,線程之間都是互相等待,區(qū)別在于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();
          ????}

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

          我是賣家,我?guī)еb備過來了!
          我是買家,我?guī)е蝗f游戲幣過來了
          賣家達(dá)到交易地點(diǎn)
          買家到達(dá)交易地點(diǎn)
          我是買家,換回了裝備
          我是賣家,換回了一萬游戲幣

          PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、轉(zhuǎn)發(fā)、在看。

          PS:歡迎在留言區(qū)留下你的觀點(diǎn),一起討論提高。如果今天的文章讓你有新的啟發(fā),歡迎轉(zhuǎn)發(fā)分享給更多人。

          瀏覽 21
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91AV免费播放 | 人妻爽爽爽| 九色自拍论坛 | 国产又黄又爽免费观看 | 欧美A欧美A |