最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解析阿里一面CyclicBarrier和CountDownLatch的區(qū)別

 更新時(shí)間:2021年03月21日 07:45:45   作者:java金融  
這篇文章主要介紹了阿里一面CyclicBarrier和CountDownLatch的區(qū)別是啥,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

引言

前面一篇文章我們《Java線程并發(fā)工具類CountDownLatch原理及用法》它有一個(gè)缺點(diǎn),就是它的計(jì)數(shù)器只能夠使用一次,也就是說(shuō)當(dāng)計(jì)數(shù)器(state)減到為 0的時(shí)候,如果 再有線程調(diào)用去 await() 方法,該線程會(huì)直接通過(guò),不會(huì)再起到等待其他線程執(zhí)行結(jié)果起到同步的作用。為了解決這個(gè)問題CyclicBarrier就應(yīng)運(yùn)而生了。

什么是CyclicBarrier

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

它的主要作用其實(shí)和CountDownLanch差不多,都是讓一組線程到達(dá)一個(gè)屏障時(shí)被阻塞,直到最后一個(gè)線程到達(dá)屏障時(shí),屏障會(huì)被打開,所有被屏障阻塞的線程才會(huì)繼續(xù)執(zhí)行,不過(guò)它是可以循環(huán)執(zhí)行的,這是它與CountDownLanch最大的不同。CountDownLanch是只有當(dāng)最后一個(gè)線程把計(jì)數(shù)器置為0的時(shí)候,其他阻塞的線程才會(huì)繼續(xù)執(zhí)行。學(xué)習(xí)CyclicBarrier之前建議先去看看這幾篇文章:

《Java高并發(fā)編程基礎(chǔ)之AQS》

《Java高并發(fā)編程基礎(chǔ)三大利器之Semaphore》

《Java高并發(fā)編程基礎(chǔ)三大利器之CountDownLatch》

如何使用

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

public class CyclicBarrierExample {
 static class PreTaskThread implements Runnable {
 private String task;
 private CyclicBarrier cyclicBarrier;

 public PreTaskThread(String task, CyclicBarrier cyclicBarrier) {
  this.task = task;
  this.cyclicBarrier = cyclicBarrier;
 }

 @Override
 public void run() {
  for (int i = 0; i < 4; i++) {
  Random random = new Random();
  try {
   Thread.sleep(random.nextInt(1000));
   System.out.println(String.format("關(guān)卡 %d 的任務(wù) %s 完成", i, task));
   cyclicBarrier.await();
  } catch (InterruptedException | BrokenBarrierException e) {
   e.printStackTrace();
  }
  }
 }

 public static void main(String[] args) {
  CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
  System.out.println("本關(guān)卡所有的前置任務(wù)完成,開始游戲... ...");
  });
  new Thread(new PreTaskThread("加載地圖數(shù)據(jù)", cyclicBarrier)).start();
  new Thread(new PreTaskThread("加載人物模型", cyclicBarrier)).start();
  new Thread(new PreTaskThread("加載背景音樂", cyclicBarrier)).start();
 }
 }
}

輸出結(jié)果如下:

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

源碼分析

結(jié)構(gòu)組成

 /** The lock for guarding barrier entry */
 private final ReentrantLock lock = new ReentrantLock();
 /** Condition to wait on until tripped */
 private final Condition trip = lock.newCondition();
 /** The number of parties */
 private final int parties;
 /* The command to run when tripped */
 private final Runnable barrierCommand;
 /** The current generation */
 private Generation generation = new Generation();
  • lock:用于保護(hù)屏障入口的鎖
  • trip :達(dá)到屏障并且不能放行的線程在trip條件變量上等待
  • parties :柵欄開啟需要的到達(dá)線程總數(shù)barrierCommand:最后一個(gè)線程到達(dá)屏障后執(zhí)行的回調(diào)任務(wù)
  • generation:這是一個(gè)內(nèi)部類,通過(guò)它實(shí)現(xiàn)CyclicBarrier重復(fù)利用,每當(dāng)await達(dá)到最大次數(shù)的時(shí)候,就會(huì)重新new 一個(gè),表示進(jìn)入了下一個(gè)輪回。里面只有一個(gè)boolean型屬性,用來(lái)表示當(dāng)前輪回是否有線程中斷。

主要方法

await方法

 public int await() throws InterruptedException, BrokenBarrierException {
 try {
  return dowait(false, 0L);
 } catch (TimeoutException toe) {
  throw new Error(toe); // cannot happen
 }
 }
 /**
 * Main barrier code, covering the various policies.
 */
 private int dowait(boolean timed, long nanos)
 throws InterruptedException, BrokenBarrierException,
  TimeoutException {
 final ReentrantLock lock = this.lock;
 lock.lock();
  try {
  //獲取barrier當(dāng)前的 “代”也就是當(dāng)前循環(huán)
  final Generation g = generation;
  if (g.broken)
  throw new BrokenBarrierException();

  if (Thread.interrupted()) {
  breakBarrier();
  throw new InterruptedException();
  }
  // 每來(lái)一個(gè)線程調(diào)用await方法都會(huì)進(jìn)行減1
  int index = --count;
  if (index == 0) { // tripped
  boolean ranAction = false;
  try {
   final Runnable command = barrierCommand;
   // new CyclicBarrier 傳入 的barrierCommand, command.run()這個(gè)方法是同步的,如果耗時(shí)比較多的話,是否執(zhí)行的時(shí)候需要考慮下是否異步來(lái)執(zhí)行。
   if (command != null)
   command.run();
   ranAction = true;
   // 這個(gè)方法1. 喚醒所有阻塞的線程,2. 重置下count(count 每來(lái)一個(gè)線程都會(huì)進(jìn)行減1)和generation,以便于下次循環(huán)。
   nextGeneration();
   return 0;
  } finally {
   if (!ranAction)
   breakBarrier();
  }
  }

  // loop until tripped, broken, interrupted, or timed out
  for (;;) {
  try {
   // 進(jìn)入if條件,說(shuō)明是不帶超時(shí)的await
   if (!timed)
    // 當(dāng)前線程會(huì)釋放掉lock,然后進(jìn)入到trip條件隊(duì)列的尾部,然后掛起自己,等待被喚醒。
   trip.await();
   else if (nanos > 0L)
    //說(shuō)明當(dāng)前線程調(diào)用await方法時(shí) 是指定了 超時(shí)時(shí)間的!
   nanos = trip.awaitNanos(nanos);
  } catch (InterruptedException ie) {
   //Node節(jié)點(diǎn)在 條件隊(duì)列內(nèi) 時(shí) 收到中斷信號(hào)時(shí) 會(huì)拋出中斷異常!
   //g == generation 成立,說(shuō)明當(dāng)前代并沒有變化。
   //! g.broken 當(dāng)前代如果沒有被打破,那么當(dāng)前線程就去打破,并且拋出異常..
   if (g == generation && ! g.broken) {
   breakBarrier();
   throw ie;
   } else {
   // We're about to finish waiting even if we had not
   // been interrupted, so this interrupt is deemed to
   // "belong" to subsequent execution.
   //執(zhí)行到else有幾種情況?
   //1.代發(fā)生了變化,這個(gè)時(shí)候就不需要拋出中斷異常了,因?yàn)?代已經(jīng)更新了,這里喚醒后就走正常邏輯了..只不過(guò)設(shè)置下 中斷標(biāo)記。
   //2.代沒有發(fā)生變化,但是代被打破了,此時(shí)也不用返回中斷異常,執(zhí)行到下面的時(shí)候會(huì)拋出 brokenBarrier異常。也記錄下中斷標(biāo)記位。
   Thread.currentThread().interrupt();
   }
  }
  //喚醒后,執(zhí)行到這里,有幾種情況?
  //1.正常情況,當(dāng)前barrier開啟了新的一代(trip.signalAll())
  //2.當(dāng)前Generation被打破,此時(shí)也會(huì)喚醒所有在trip上掛起的線程
  //3.當(dāng)前線程trip中等待超時(shí),然后主動(dòng)轉(zhuǎn)移到 阻塞隊(duì)列 然后獲取到鎖 喚醒。
  if (g.broken)
   throw new BrokenBarrierException();
  //喚醒后,執(zhí)行到這里,有幾種情況?
  //1.正常情況,當(dāng)前barrier開啟了新的一代(trip.signalAll())
  //2.當(dāng)前線程trip中等待超時(shí),然后主動(dòng)轉(zhuǎn)移到 阻塞隊(duì)列 然后獲取到鎖 喚醒。
  if (g != generation)
   return index;
  //喚醒后,執(zhí)行到這里,有幾種情況?
  //.當(dāng)前線程trip中等待超時(shí),然后主動(dòng)轉(zhuǎn)移到 阻塞隊(duì)列 然后獲取到鎖 喚醒。
  if (timed && nanos <= 0L) {
   breakBarrier();
   throw new TimeoutException();
  }
  }
 } finally {
  lock.unlock();
 }
 }

小結(jié)

到了這里我們是不是可以知道為啥CyclicBarrier可以進(jìn)行循環(huán)計(jì)數(shù)?
CyclicBarrier采用一個(gè)內(nèi)部類Generation來(lái)維護(hù)當(dāng)前循環(huán),每一個(gè)await方法都會(huì)存儲(chǔ)當(dāng)前的generation,獲取到相同generation對(duì)象的屬于同一組,每當(dāng)count的次數(shù)耗盡就會(huì)重新new一個(gè)Generation并且重新設(shè)置count的值為parties,表示進(jìn)入下一次新的循環(huán)。
從這個(gè)await方法我們是不是可以知道只要有一個(gè)線程被中斷了,當(dāng)代的 generationbroken 就會(huì)被設(shè)置為true,所以會(huì)導(dǎo)致其他的線程也會(huì)被拋出BrokenBarrierException。相當(dāng)于一個(gè)失敗其他也必須失敗,感覺有“強(qiáng)一致性“的味道。

總結(jié)

CountDownLanch是為計(jì)數(shù)器是設(shè)置一個(gè)值,當(dāng)多次執(zhí)行countdown后,計(jì)數(shù)器減為0的時(shí)候所有線程被喚醒,然后CountDownLanch失效,只能夠使用一次。

CyclicBarrier是當(dāng)count0時(shí)同樣喚醒全部線程,同時(shí)會(huì)重新設(shè)置countparties,重新new一個(gè)generation來(lái)實(shí)現(xiàn)重復(fù)利用。

結(jié)束

  • 由于自己才疏學(xué)淺,難免會(huì)有紕漏,假如你發(fā)現(xiàn)了錯(cuò)誤的地方,還望留言給我指出來(lái),我會(huì)對(duì)其加以修正。
  • 如果你覺得文章還不錯(cuò),你的轉(zhuǎn)發(fā)、分享、贊賞、點(diǎn)贊、留言就是對(duì)我最大的鼓勵(lì)。感
  • 謝您的閱讀,十分歡迎并感謝您的關(guān)注。

巨人的肩膀摘蘋果

https://javajr.cn/
http://www.360doc.com/content/20/0812/08/55930996_929792021.shtml
https://www.cnblogs.com/xxyyy/p/12958160.html

到此這篇關(guān)于阿里一面CyclicBarrier和CountDownLatch的區(qū)別是啥的文章就介紹到這了,更多相關(guān)CyclicBarrier和CountDownLatch的區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot和Vue實(shí)現(xiàn)動(dòng)態(tài)二維碼的示例代碼

    SpringBoot和Vue實(shí)現(xiàn)動(dòng)態(tài)二維碼的示例代碼

    二維碼在現(xiàn)代社交和營(yíng)銷活動(dòng)中被廣泛使用,本文主要介紹了SpringBoot和Vue實(shí)現(xiàn)動(dòng)態(tài)二維碼的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02
  • java使用dom4j解析xml配置文件實(shí)現(xiàn)抽象工廠反射示例

    java使用dom4j解析xml配置文件實(shí)現(xiàn)抽象工廠反射示例

    本文主要介紹了java使用dom4j讀取配置文件實(shí)現(xiàn)抽象工廠和反射的示例,在Java中也可以同Donet一樣,將差異配置在配置文件里面。另外,我們采用下面的方式實(shí)現(xiàn),將會(huì)更加便捷
    2014-01-01
  • Java 超詳細(xì)講解hashCode方法

    Java 超詳細(xì)講解hashCode方法

    在 Java 應(yīng)用程序執(zhí)行期間,在同一對(duì)象上多次調(diào)用 hashCode 方法時(shí),必須一致地返回相同的整數(shù),前提是對(duì)象上 equals 比較中所用的信息沒有被修改。從某一應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行,該整數(shù)無(wú)需保持一致
    2022-04-04
  • Java中對(duì)象序列化與反序列化詳解

    Java中對(duì)象序列化與反序列化詳解

    這篇文章主要介紹了Java中對(duì)象序列化與反序列化,較為詳細(xì)的分析了java中對(duì)象序列化的概念、原理、實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • datax-web在windows環(huán)境idea中模塊化打包部署操作步驟

    datax-web在windows環(huán)境idea中模塊化打包部署操作步驟

    這篇文章主要介紹了datax-web在windows環(huán)境idea中模塊化打包部署操作步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • SpringBoot+Redis實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)的示例

    SpringBoot+Redis實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)的示例

    本文將結(jié)合實(shí)例代碼,介紹SpringBoot+Redis實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)的示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java中使用DOM4J生成xml文件并解析xml文件的操作

    Java中使用DOM4J生成xml文件并解析xml文件的操作

    這篇文章主要介紹了Java中使用DOM4J來(lái)生成xml文件和解析xml文件的操作,今天通過(guò)代碼給大家展示了解析xml文件和生成xml文件的方法,需要的朋友可以參考下
    2021-09-09
  • Java中JDK14的新特性之JFR,JMC和JFR事件流(推薦)

    Java中JDK14的新特性之JFR,JMC和JFR事件流(推薦)

    JFR是一個(gè)基于事件的低開銷的分析引擎,具有高性能的后端,可以以二進(jìn)制格式編寫事件,而JMC是一個(gè)GUI工具,用于檢查JFR創(chuàng)建的數(shù)據(jù)文件。本文給大家介紹Java中JDK14的新特性之JFR,JMC和JFR事件流的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2020-05-05
  • 理解java設(shè)計(jì)模式之建造者模式

    理解java設(shè)計(jì)模式之建造者模式

    這篇文章主要幫助大家理解java設(shè)計(jì)模式之建造者模式,對(duì)建造者模式,即生成器模式進(jìn)行實(shí)例講解,感興趣的朋友可以參考一下
    2016-02-02
  • java求余的技巧匯總

    java求余的技巧匯總

    這篇文章主要給大家介紹了關(guān)于java求余技巧的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09

最新評(píng)論

和田县| 田阳县| 台南县| 岳普湖县| 揭西县| 枣阳市| 西乌| 磐石市| 济阳县| 鄂州市| 江安县| 娄底市| 枣阳市| 广河县| 同仁县| 德庆县| 乌兰县| 巴青县| 保山市| 和静县| 林甸县| 宣化县| 比如县| 宜都市| 樟树市| 长海县| 连南| 甘孜县| 崇阳县| 缙云县| 苗栗县| 河池市| 涡阳县| 南投市| 桐城市| 德令哈市| 邵东县| 鲜城| 阳山县| 左云县| 兴安县|