成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java高并發編程基礎三大利器之CyclicBarrier

開發 后端
前面一篇文章我們《Java高并發編程基礎三大利器之CountDownLatch》它有一個缺點,就是它的計數器只能夠使用一次,也就是說當計數器(state)減到為 0的時候,如果 再有線程調用去 await() 方法,該線程會直接通過,不會再起到等待其他線程執行結果起到同步的作用。

 [[388240]]

引言

前面一篇文章我們《Java高并發編程基礎三大利器之CountDownLatch》它有一個缺點,就是它的計數器只能夠使用一次,也就是說當計數器(state)減到為 0的時候,如果 再有線程調用去 await() 方法,該線程會直接通過,不會再起到等待其他線程執行結果起到同步的作用。為了解決這個問題CyclicBarrier就應運而生了。

什么是CyclicBarrier

CyclicBarrier是什么?把它拆開來翻譯就是循環(Cycle)和屏障(Barrier)

它的主要作用其實和CountDownLanch差不多,都是讓一組線程到達一個屏障時被阻塞,直到最后一個線程到達屏障時,屏障會被打開,所有被屏障阻塞的線程才會繼續執行,不過它是可以循環執行的,這是它與CountDownLanch最大的不同。CountDownLanch是只有當最后一個線程把計數器置為0的時候,其他阻塞的線程才會繼續執行。學習CyclicBarrier之前建議先去看看這幾篇文章:

Java高并發編程基礎之AQS

Java高并發編程基礎三大利器之Semaphore

Java高并發編程基礎三大利器之CountDownLatch

如何使用

我們首先先來看下關于使用CyclicBarrier的一個demo:比如游戲中有個關卡的時候,每次進入下一關的時候都需要進行加載一些地圖、特效背景音樂什么的只有全部加載完了才能夠進行游戲:

  1. /**demo 來源https://blog.csdn.net/lstcui/article/details/107389371 
  2.  * 公眾號【java金融】 
  3.  */ 
  4. public class CyclicBarrierExample { 
  5.     static class PreTaskThread implements Runnable { 
  6.         private String task; 
  7.         private CyclicBarrier cyclicBarrier; 
  8.  
  9.         public PreTaskThread(String task, CyclicBarrier cyclicBarrier) { 
  10.             this.task = task; 
  11.             this.cyclicBarrier = cyclicBarrier; 
  12.         } 
  13.  
  14.         @Override 
  15.         public void run() { 
  16.             for (int i = 0; i < 4; i++) { 
  17.                 Random random = new Random(); 
  18.                 try { 
  19.                     Thread.sleep(random.nextInt(1000)); 
  20.                     System.out.println(String.format("關卡 %d 的任務 %s 完成", i, task)); 
  21.                     cyclicBarrier.await(); 
  22.                 } catch (InterruptedException | BrokenBarrierException e) { 
  23.                     e.printStackTrace(); 
  24.                 } 
  25.             } 
  26.         } 
  27.  
  28.         public static void main(String[] args) { 
  29.             CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> { 
  30.                 System.out.println("本關卡所有的前置任務完成,開始游戲... ..."); 
  31.             }); 
  32.             new Thread(new PreTaskThread("加載地圖數據", cyclicBarrier)).start(); 
  33.             new Thread(new PreTaskThread("加載人物模型", cyclicBarrier)).start(); 
  34.             new Thread(new PreTaskThread("加載背景音樂", cyclicBarrier)).start(); 
  35.         } 
  36.     } 

輸出結果如下:

我們可以看到每次游戲開始都會等當前關卡把游戲的人物模型,地圖數據、背景音樂加載完成后才會開始進行游戲。并且還是可以循環控制的。

源碼分析

結構組成

  1. /** The lock for guarding barrier entry */ 
  2. private final ReentrantLock lock = new ReentrantLock(); 
  3. /** Condition to wait on until tripped */ 
  4. private final Condition trip = lock.newCondition(); 
  5. /** The number of parties */ 
  6. private final int parties; 
  7. /* The command to run when tripped */ 
  8. private final Runnable barrierCommand; 
  9. /** The current generation */ 
  10. private Generation generation = new Generation(); 
  • lock:用于保護屏障入口的鎖
  • trip :達到屏障并且不能放行的線程在trip條件變量上等待
  • parties :柵欄開啟需要的到達線程總數
  • barrierCommand:最后一個線程到達屏障后執行的回調任務
  • generation:這是一個內部類,通過它實現CyclicBarrier重復利用,每當await達到最大次數的時候,就會重新new 一個,表示進入了下一個輪回。里面只有一個boolean型屬性,用來表示當前輪回是否有線程中斷。

主要方法

  1. public int await() throws InterruptedException, BrokenBarrierException { 
  2.     try { 
  3.         return dowait(false, 0L); 
  4.     } catch (TimeoutException toe) { 
  5.         throw new Error(toe); // cannot happen 
  6.     } 
  7.  
  8.  * Main barrier code, covering the various policies. 
  9.  */ 
  10. private int dowait(boolean timed, long nanos) 
  11.     throws InterruptedException, BrokenBarrierException, 
  12.            TimeoutException { 
  13.     final ReentrantLock lock = this.lock; 
  14.     lock.lock(); 
  15.      try { 
  16.            //獲取barrier當前的 “代”也就是當前循環 
  17.          final Generation g = generation; 
  18.         if (g.broken) 
  19.             throw new BrokenBarrierException(); 
  20.  
  21.         if (Thread.interrupted()) { 
  22.             breakBarrier(); 
  23.             throw new InterruptedException(); 
  24.         } 
  25.         // 每來一個線程調用await方法都會進行減1 
  26.         int index = --count; 
  27.         if (index == 0) {  // tripped 
  28.             boolean ranAction = false
  29.             try { 
  30.                 final Runnable command = barrierCommand; 
  31.                 // new CyclicBarrier 傳入 的barrierCommand, command.run()這個方法是同步的,如果耗時比較多的話,是否執行的時候需要考慮下是否異步來執行。 
  32.                 if (command != null
  33.                     command.run(); 
  34.                 ranAction = true
  35.                 // 這個方法1. 喚醒所有阻塞的線程,2. 重置下countcount 每來一個線程都會進行減1)和generation,以便于下次循環。 
  36.                 nextGeneration(); 
  37.                 return 0; 
  38.             } finally { 
  39.                 if (!ranAction) 
  40.                     breakBarrier(); 
  41.             } 
  42.         } 
  43.  
  44.         // loop until tripped, broken, interrupted, or timed out 
  45.         for (;;) { 
  46.             try { 
  47.                  // 進入if條件,說明是不帶超時的await 
  48.                 if (!timed) 
  49.                      // 當前線程會釋放掉lock,然后進入到trip條件隊列的尾部,然后掛起自己,等待被喚醒。 
  50.                     trip.await(); 
  51.                 else if (nanos > 0L) 
  52.                      //說明當前線程調用await方法時 是指定了 超時時間的! 
  53.                     nanos = trip.awaitNanos(nanos); 
  54.             } catch (InterruptedException ie) { 
  55.                  //Node節點在 條件隊列內 時 收到中斷信號時 會拋出中斷異常! 
  56.                 //g == generation 成立,說明當前代并沒有變化。 
  57.                 //! g.broken 當前代如果沒有被打破,那么當前線程就去打破,并且拋出異常.. 
  58.                 if (g == generation && ! g.broken) { 
  59.                     breakBarrier(); 
  60.                     throw ie; 
  61.                 } else { 
  62.                     // We're about to finish waiting even if we had not 
  63.                     // been interrupted, so this interrupt is deemed to 
  64.                     // "belong" to subsequent execution. 
  65.                 //執行到else有幾種情況? 
  66.                 //1.代發生了變化,這個時候就不需要拋出中斷異常了,因為 代已經更新了,這里喚醒后就走正常邏輯了..只不過設置下 中斷標記。 
  67.                 //2.代沒有發生變化,但是代被打破了,此時也不用返回中斷異常,執行到下面的時候會拋出  brokenBarrier異常。也記錄下中斷標記位。 
  68.                     Thread.currentThread().interrupt(); 
  69.                 } 
  70.             } 
  71.            //喚醒后,執行到這里,有幾種情況? 
  72.           //1.正常情況,當前barrier開啟了新的一代(trip.signalAll()) 
  73.           //2.當前Generation被打破,此時也會喚醒所有在trip上掛起的線程 
  74.           //3.當前線程trip中等待超時,然后主動轉移到 阻塞隊列 然后獲取到鎖 喚醒。 
  75.             if (g.broken) 
  76.                 throw new BrokenBarrierException(); 
  77.            //喚醒后,執行到這里,有幾種情況? 
  78.         //1.正常情況,當前barrier開啟了新的一代(trip.signalAll()) 
  79.         //2.當前線程trip中等待超時,然后主動轉移到 阻塞隊列 然后獲取到鎖 喚醒。 
  80.             if (g != generation) 
  81.                 return index
  82.            //喚醒后,執行到這里,有幾種情況? 
  83.         //.當前線程trip中等待超時,然后主動轉移到 阻塞隊列 然后獲取到鎖 喚醒。 
  84.             if (timed && nanos <= 0L) { 
  85.                 breakBarrier(); 
  86.                 throw new TimeoutException(); 
  87.             } 
  88.         } 
  89.     } finally { 
  90.          lock.unlock(); 
  91.     } 

小結

到了這里我們是不是可以知道為啥CyclicBarrier可以進行循環計數?

  • CyclicBarrier采用一個內部類Generation來維護當前循環,每一個await方法都會存儲當前的generation,獲取到相同generation對象的屬于同一組,每當count的次數耗盡就會重新new一個Generation并且重新設置count的值為parties,表示進入下一次新的循環。

從這個await方法我們是不是可以知道只要有一個線程被中斷了,當代的 generation的broken 就會被設置為true,所以會導致其他的線程也會被拋出BrokenBarrierException。相當于一個失敗其他也必須失敗,感覺有“強一致性“的味道。

總結

  • CountDownLanch是為計數器是設置一個值,當多次執行countdown后,計數器減為0的時候所有線程被喚醒,然后CountDownLanch失效,只能夠使用一次。
  • CyclicBarrier是當count為0時同樣喚醒全部線程,同時會重新設置count為parties,重新new一個generation來實現重復利用。

本文轉載自微信公眾號「java金融」,可以通過以下二維碼關注。轉載本文請聯系java金融公眾號。

 

責任編輯:武曉燕 來源: java金融
相關推薦

2021-03-11 00:05:55

Java高并發編程

2021-03-04 07:24:24

JavaSemaphore高并發

2020-08-27 08:17:05

緩存高并發系統

2021-02-26 13:08:27

Java高并發AQS

2024-04-29 09:06:46

線程初始化源碼

2014-03-14 10:34:28

JavaJava并發

2019-09-16 09:23:34

高并發編程CountDownLaCyclicBarri

2020-12-03 11:15:21

CyclicBarri

2025-06-18 08:10:00

Java并發編程開發

2022-07-02 08:40:00

并發編程

2024-11-21 14:55:37

2020-09-21 06:53:41

NoSQL高并發面試

2022-11-27 08:12:11

RocketMQ源碼工具類

2024-04-02 09:40:39

多線程Java原子性

2019-11-07 09:20:29

Java線程操作系統

2024-12-27 09:08:25

2021-08-05 07:58:22

并發編程包Task

2011-07-05 14:42:46

java

2024-09-02 22:49:33

2016-11-28 09:08:43

java系統異步非阻塞
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本人做爰大片免费观看一老师 | 亚洲激情一区二区 | 欧美日韩免费 | 久久国产成人精品国产成人亚洲 | 国产精产国品一二三产区视频 | 国产精品观看 | 国产免费一区二区三区网站免费 | 国产精品视频一区二区三区 | 污视频在线免费观看 | 九九热精品视频在线观看 | 成人欧美一区二区三区黑人孕妇 | 中文字幕在线视频免费视频 | 91在线一区| 日韩乱码在线 | caoporn免费 | 欧美日韩在线电影 | 欧美精品在线一区 | www.4hu影院 | 国产区一区二区三区 | 亚洲成在线观看 | 欧美精品一区二区三区一线天视频 | 日韩免费一区二区 | 一区二区亚洲 | 国产精品久久99 | 色成人免费网站 | 一区二区三区四区在线视频 | 91福利网址 | 成人免费一区二区三区视频网站 | 欧美日韩成人影院 | 一区二区三区四区av | 97久久久| 91在线一区| 欧美成人一区二区三区片免费 | 欧美日韩精品一区二区三区蜜桃 | 亚洲手机视频在线 | 午夜免费福利电影 | 久久一区二区免费视频 | 亚洲精品久久久一区二区三区 | 国产精品毛片av | 国产一区二区 | 婷婷久|