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

          一文搞懂四種同步工具類

          共 2711字,需瀏覽 6分鐘

           ·

          2021-10-20 07:22

          點擊關注公眾號,回復“2T”獲取2TB學習資源!
          互聯(lián)網架構師后臺回復?2T?有特別禮包

          作者:CoderV的進階筆記

          來源:juejin.cn/post/6844903958360621064
          上一篇:深夜看了張一鳴的微博,讓我越想越后怕

          CountDownLatch

          解釋:

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

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

          代碼:

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

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

          CyclicBarrier

          解釋:

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

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

          我們舉一個例子,兩個選手進行比賽,一共進行三輪比賽。

          代碼:

          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ā)表關于這篇文章的任何建議,關注我,技術不迷茫!小編到你上高速。

          ??? · END ·
          最后,關注公眾號互聯(lián)網架構師,在后臺回復:2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全


          正文結束


          推薦閱讀 ↓↓↓

          1.不認命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵志故事

          2.如何才能成為優(yōu)秀的架構師?

          3.從零開始搭建創(chuàng)業(yè)公司后臺技術棧

          4.程序員一般可以從什么平臺接私活?

          5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結果懵了...

          6.IntelliJ IDEA 2019.3 首個最新訪問版本發(fā)布,新特性搶先看

          7.這封“領導痛批95后下屬”的郵件,句句扎心!

          8.15張圖看懂瞎忙和高效的區(qū)別!

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  老司机综合网 | 三级成人网站在线观看 | 成人黄色片在线免费看 | 天天天做夜夜夜夜爽无码 | 免费一级a|