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

          CountDownLunch(閉鎖)、CyclicBarrier(柵欄鎖)、Semaphore(信號量)的區(qū)別

          共 7703字,需瀏覽 16分鐘

           ·

          2024-05-31 22:02

          CountDownLunch

          countDownLunch,又叫閉鎖。它有三個(gè)關(guān)鍵的api:

          • new CountDownLatch(count); 創(chuàng)建一個(gè)閉鎖,并聲明count的值
          • countDownLatch.await();如果countDownLunch的count不是0,則阻塞當(dāng)前線程直到count等0
          • countDownLatch.countDown();將countDownLunch中的count減一

          代碼樣例:

          Logger logger = LoggerFactory.getLogger(this.getClass());
          //創(chuàng)建一個(gè)count=1的閉鎖
          CountDownLatch countDownLatch = new CountDownLatch(1);
          List<Thread> threads = new ArrayList<>();
          //創(chuàng)建5個(gè)線程
          for (int i = 0; i < 5; i++) {
           Thread thread = new Thread(() -> {
            logger.info("[{}]在等待發(fā)令槍", Thread.currentThread().getName());
            try {
             //等待閉鎖的count=0
             countDownLatch.await();
            } catch (InterruptedException e) {
             e.printStackTrace();
            }
            logger.info("槍響了,[{}]跑!", Thread.currentThread().getName());
           }, "t" + (i + 1));
           thread.start();
           threads.add(thread);
           try {
            //讓出CPU
            TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }
          logger.info("開槍,開跑!");
          //將count--
          countDownLatch.countDown();
          try {
           //讓出CPU
           TimeUnit.SECONDS.sleep(1);
          } catch (InterruptedException e) {
           e.printStackTrace();
          }
          //循環(huán)等待所有線程結(jié)束
          for (Thread thread : threads) {
           try {
            thread.join();
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }

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

          從結(jié)果中可以看出來,t1~t5是同時(shí)開跑的。需要注意的是,countDownLatch.await();會在count的值等于0時(shí),喚醒被阻塞的線程,但是被喚醒的線程是否馬上就可執(zhí)行,這個(gè)要看CPU的調(diào)度,不一定被喚醒后,馬上就可以執(zhí)行。

          上面是多等一的用法,下面來一個(gè)一等多的用法:

          public static void main(String[] args) {
           int count = 5;
           CountDownLatch countDownLatch = new CountDownLatch(count);
           String[] list = new String[count];
           Random random = new Random();
           for (int i = 0; i < count; i++) {
               int finalI = i;
               Thread thread = new Thread(() -> {
                   for (int j = 0; j <= 100; j++) {
                       try {
                           TimeUnit.MILLISECONDS.sleep(random.nextInt(200));
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       list[finalI]= Thread.currentThread().getName()+"("+j+"%)";
                       System.out.print("\r"+ Arrays.toString(list));
                   }
                   countDownLatch.countDown();
               }, "t" + (i + 1));
               thread.start();
           }
           try {
               countDownLatch.await();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.print("\n結(jié)束了");
          }

          結(jié)果如下:

          與join相比相同點(diǎn):

          都可以在某種程度上等待線程執(zhí)行完畢

          與join相比不同點(diǎn):

          • join是Thread的方法,需要持有Thread的引用,但是現(xiàn)在很多時(shí)候都是像線程池中提交任務(wù)的,很難拿到這個(gè)Thread的引用。但是CountDownLunch是可以作為全局變量的,這個(gè)引用比較好拿到。

          • join是一定要等待線程結(jié)束的,但是CountDownLunch還是比較靈活的,可以在任意時(shí)刻countDown。

          CyclicBarrier

          CyclicBarrier,又叫柵欄鎖

          Logger logger = LoggerFactory.getLogger(this.getClass());
          CyclicBarrier cyclicBarrier = new CyclicBarrier(2, ()->{
           logger.info("cyclicBarrier被置為0了,{}",Thread.currentThread().getName());
          });
          logger.info("cyclicBarrier初始化為2,{}",Thread.currentThread().getName());
          List<Thread> threads = new ArrayList<>();
          for (int i = 0; i < 4; i++) {
           Thread thread = new Thread(() -> {
            logger.info("cyclicBarrier -1,[{}]",Thread.currentThread().getName());
            try {
             cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
             e.printStackTrace();
            }
            logger.info("cyclicBarrier 0了,[{}]",Thread.currentThread().getName());
           }, "t" + (i + 1));
           thread.start();
           threads.add(thread);
           try {
            TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }
          //循環(huán)等待所有線程結(jié)束
          for (Thread thread : threads) {
           try {
            thread.join();
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }

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

          從執(zhí)行結(jié)果可以看出來,cyclicBarrier是可以循環(huán)使用的,當(dāng)cyclicBarrier的值=0時(shí),會調(diào)用CyclicBarrier構(gòu)造器中的runnable同時(shí)會將count重置為一開始設(shè)定的值。與countDownLunch相比:

          相同點(diǎn):

          在count不等于0時(shí),調(diào)用await的線程也是會阻塞的。

          不同點(diǎn):

          • cyclicBarrier可以循環(huán)使用,countDownLunch是一次性的

          • cyclicBarrier只要調(diào)用await就會使count-1,但是countDownLunch需要手動調(diào)用countDown方法

          Semaphore

          Semaphore,又叫信號量

          信號量是用來限制一個(gè)時(shí)間點(diǎn)下,使用某資源的最大線程數(shù)。信號量限制的是線程數(shù),而不是資源數(shù)。

          Semaphore semaphore = new Semaphore(3);
          Logger logger = LoggerFactory.getLogger(this.getClass());
          logger.info("初始化了一個(gè)大小為3的信號量。");
          List<Thread> threads = new ArrayList<>();
          for (int i = 0; i < 5; i++) {
           Thread thread = new Thread(() -> {
            logger.info("[{}]嘗試申請一個(gè)資源",Thread.currentThread().getName());
            try {
             semaphore.acquire();
             logger.info("[{}]申請到了資源",Thread.currentThread().getName());
            } catch (InterruptedException e) {
             e.printStackTrace();
            }
            try {
             TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
             e.printStackTrace();
            }
            logger.info("[{}]釋放了一個(gè)資源",Thread.currentThread().getName());
            semaphore.release();
           }, "t" + (i + 1));
           thread.start();
           threads.add(thread);
           try {
            //讓出CPU
            TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }
          //循環(huán)等待所有線程結(jié)束
          for (Thread thread : threads) {
           try {
            thread.join();
           } catch (InterruptedException e) {
            e.printStackTrace();
           }
          }

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

          在上面的代碼中,首先創(chuàng)建了一個(gè)大小為3的信號量,然后創(chuàng)建了5個(gè)線程去依次申請資源。從日志中可以看出,線程123都順利的拿到了資源,但是線程45在申請資源時(shí)發(fā)生了阻塞,當(dāng)t1釋放資源時(shí),t4先獲取到資源,t2釋放資源時(shí),t5獲取到了資源。

          瀏覽 50
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  久爱青草视频 | 亚洲日韩欧美电影 | 人人肏逼| 色婷婷五月天影院 | 熟女久久久99 |