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

詳解Java回環(huán)屏障CyclicBarrier

 更新時(shí)間:2020年09月12日 10:48:50   作者:java小新人  
這篇文章主要介紹了Java回環(huán)屏障CyclicBarrier的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下

  上一篇說的CountDownLatch是一個(gè)計(jì)數(shù)器,類似線程的join方法,但是有一個(gè)缺陷,就是當(dāng)計(jì)數(shù)器的值到達(dá)0之后,再調(diào)用CountDownLatch的await和countDown方法就會(huì)立刻返回,就沒有作用了,那么反正是一個(gè)計(jì)數(shù)器,為什么不能重復(fù)使用呢?于是就出現(xiàn)了這篇說的CyclicBarrier,它的狀態(tài)可以被重用;

一.簡單例子

  用法其實(shí)和CountDownLatch差不多,也就是一個(gè)計(jì)數(shù)器,當(dāng)計(jì)數(shù)器的值變?yōu)?之后,就會(huì)把阻塞的線程喚醒:

package com.example.demo.study;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Study0216 {
 // 注意這里的構(gòu)造器,第一個(gè)參數(shù)表示計(jì)數(shù)器初始值
 // 第二個(gè)參數(shù)表示當(dāng)計(jì)數(shù)器的值變?yōu)?的時(shí)候就觸發(fā)的任務(wù)
 static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
  System.out.println("cyclicBarrier task ");
 });

 public static void main(String[] args) {
  // 新建兩個(gè)線程的線程池
  ExecutorService pool = Executors.newFixedThreadPool(2);
  // 線程1放入線程池中
  pool.submit(() -> {
   try {
    System.out.println("Thread1----await-begin");
    cyclicBarrier.await();
    System.out.println("Thread1----await-end");
   } catch (Exception e) {
    e.printStackTrace();
   }
  });
  // 線程2放到線程池中
  pool.submit(() -> {
   try {
    System.out.println("Thread2----await-begin");
    cyclicBarrier.await();
    System.out.println("Thread2----await-end");
   } catch (Exception e) {
    e.printStackTrace();
   }
  });
  // 關(guān)閉線程池,此時(shí)還在執(zhí)行的任務(wù)會(huì)繼續(xù)執(zhí)行
  pool.shutdown();
 }
}

 我們再看看CyclicBarrier的復(fù)用性,這里比如有一個(gè)任務(wù),有三部分組成,分別是A,B,C,然后創(chuàng)建兩個(gè)線程去執(zhí)行這個(gè)任務(wù),必須要等到兩個(gè)線程都執(zhí)行完成A部分,然后才能開始執(zhí)行B,只有兩個(gè)線程都執(zhí)行完成B部分,才能執(zhí)行C:

package com.example.demo.study;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Study0216 {
 // 這里的構(gòu)造器,只有一個(gè)參數(shù),表示計(jì)數(shù)器初始值
 static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

 public static void main(String[] args) {
  // 新建兩個(gè)線程的線程池
  ExecutorService pool = Executors.newFixedThreadPool(2);
  // 線程1放入線程池中
  pool.submit(() -> {
   try {
    System.out.println("Thread1----stepA-start");
    cyclicBarrier.await();
    
    System.out.println("Thread1----stepB-start");
    cyclicBarrier.await();
    
    System.out.println("Thread1----stepC-start");
    
    
   } catch (Exception e) {
    e.printStackTrace();
   }
  });
  // 線程2放到線程池中
  pool.submit(() -> {
   try {
    System.out.println("Thread2----stepA-start");
    cyclicBarrier.await();
    
    System.out.println("Thread2----stepB-start");
    cyclicBarrier.await();
    
    System.out.println("Thread2----stepC-start");
   } catch (Exception e) {
    e.printStackTrace();
   }
  });
  // 關(guān)閉線程池,此時(shí)還在執(zhí)行的任務(wù)會(huì)繼續(xù)執(zhí)行
  pool.shutdown();
 }
}

二.基本原理

  我們看看一些重要屬性:

public class CyclicBarrier {
 //這個(gè)內(nèi)部類只有一個(gè)boolean值
 private static class Generation {
  boolean broken = false;
 }

 //獨(dú)占鎖
 private final ReentrantLock lock = new ReentrantLock();
  //條件變量
 private final Condition trip = lock.newCondition();
  //保存線程的總數(shù)
 private final int parties;
 //這是一個(gè)任務(wù),通過構(gòu)造器傳遞一個(gè)任務(wù),當(dāng)計(jì)數(shù)器變?yōu)?之后,就可以執(zhí)行這個(gè)任務(wù)
 private final Runnable barrierCommand;
 //這類內(nèi)部之后一個(gè)boolean的值,表示屏障是否被打破
 private Generation generation = new Generation();
 //計(jì)數(shù)器
 private int count;
}

  構(gòu)造器:

//我們的構(gòu)造器初始值設(shè)置的是parties
public CyclicBarrier(int parties) {
 this(parties, null);
}
//注意,這里開始的時(shí)候是count等于parties
//為什么要有兩個(gè)變量呢?我們每次調(diào)用await方法的時(shí)候count減一,當(dāng)count的值變?yōu)?之后,怎么又還原成初始值呢?
//直接就把parties的值賦值給count就行了呀,簡單吧!
public CyclicBarrier(int parties, Runnable barrierAction) {
 if (parties <= 0) throw new IllegalArgumentException();
 this.parties = parties;
 this.count = parties;
 this.barrierCommand = barrierAction;
}

  然后再看看await方法:

public int await() throws InterruptedException, BrokenBarrierException {
 try {
  //調(diào)用的是dowait方法
  return dowait(false, 0L);
 } catch (TimeoutException toe) {
  throw new Error(toe); // cannot happen
 }
}

//假設(shè)count等于3,有三個(gè)線程都在調(diào)用這個(gè)方法,默認(rèn)超時(shí)時(shí)間為0,那么首每次都只有一個(gè)線程可以獲取鎖,將count減一,不為0
//就會(huì)到下面的for循環(huán)中扔到條件隊(duì)列中掛起;直到第三個(gè)線程調(diào)用這個(gè)dowait方法,count減一等于0,那么當(dāng)前線程執(zhí)行任務(wù)之后,
//就會(huì)喚醒條件變量中阻塞的線程,并重置count為初始值3
private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException, TimeoutException {
 //獲取鎖
 final ReentrantLock lock = this.lock;
 lock.lock();
 try {
  //g中只有一個(gè)boolean值
  final Generation g = generation;
  //如果g中的值為true的時(shí)候,拋錯(cuò)
  if (g.broken)
   throw new BrokenBarrierException();
  //如果當(dāng)前線程中斷,就拋錯(cuò)
  if (Thread.interrupted()) {
   breakBarrier();
   throw new InterruptedException();
  }
  //count減一,再賦值給index
  int index = --count;
  //如果index等于0的時(shí)候,說明所有的線程已經(jīng)到屏障點(diǎn)了,就可以
  if (index == 0) { // tripped
   boolean ranAction = false;
   try {
    //執(zhí)行當(dāng)前線程的任務(wù)
    final Runnable command = barrierCommand;
    if (command != null)
     command.run();
    ranAction = true;
    //喚醒其他因?yàn)檎{(diào)用了await方法阻塞的線程
    nextGeneration();
    return 0;
   } finally {
    if (!ranAction)
     breakBarrier();
   }
  }
  //能到這里來,說明是count不等于0,也就是還有的線程沒有到屏障點(diǎn)
  for (;;) {
   try {
    //wait方法有兩種情況,一種是設(shè)置超時(shí)時(shí)間,一種是不設(shè)置超時(shí)時(shí)間
    //這里就是對(duì)超時(shí)時(shí)間進(jìn)行的一個(gè)判斷,如果設(shè)置的超時(shí)時(shí)間為0,則會(huì)在條件隊(duì)列中無限的等待下去,直到被喚醒
    //設(shè)置了超時(shí)時(shí)間,那就等待該時(shí)間
    if (!timed)
     trip.await();
    else if (nanos > 0L)
     nanos = trip.awaitNanos(nanos);
   } catch (InterruptedException ie) {
    if (g == generation && ! g.broken) {
     breakBarrier();
     throw ie;
    } else {
     Thread.currentThread().interrupt();
    }
   }

   if (g.broken)
    throw new BrokenBarrierException();

   if (g != generation)
    return index;

   if (timed && nanos <= 0L) {
    breakBarrier();
    throw new TimeoutException();
   }
  }
 } finally {
  //釋放鎖
  lock.unlock();
 }
}

//喚醒其他因?yàn)檎{(diào)用了await方法阻塞的線程
private void nextGeneration() {
 //喚醒條件變量中所有線程
 trip.signalAll();
 //重置count的值
 count = parties;
 generation = new Generation();
}

private void breakBarrier() {
 generation.broken = true;
 //重置count為初始值parties
 count = parties;
 //喚醒條件隊(duì)列中的所有線程
 trip.signalAll();
}

以上就是詳解Java回環(huán)屏障CyclicBarrier的詳細(xì)內(nèi)容,更多關(guān)于Java CyclicBarrier的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java實(shí)現(xiàn)經(jīng)典游戲泡泡堂的示例代碼

    Java實(shí)現(xiàn)經(jīng)典游戲泡泡堂的示例代碼

    這篇文章將利用Java制作經(jīng)典游戲——泡泡堂,游戲設(shè)計(jì)為雙人pk積分賽模式,在這個(gè)模式里面,玩家只要率先達(dá)到一定分?jǐn)?shù)既可以贏得比賽。感興趣的可以了解一下
    2022-04-04
  • Java實(shí)現(xiàn)XML與JSON秒級(jí)轉(zhuǎn)換示例詳解

    Java實(shí)現(xiàn)XML與JSON秒級(jí)轉(zhuǎn)換示例詳解

    這篇文章主要為大家介紹了Java實(shí)現(xiàn)XML與JSON秒級(jí)轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 利用Spring MVC+Mybatis實(shí)現(xiàn)Mysql分頁數(shù)據(jù)查詢的過程詳解

    利用Spring MVC+Mybatis實(shí)現(xiàn)Mysql分頁數(shù)據(jù)查詢的過程詳解

    這篇文章主要給大家介紹了關(guān)于利用Spring MVC+Mybatis實(shí)現(xiàn)Mysql分頁數(shù)據(jù)查詢的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • MybatisPlus開啟二級(jí)緩存的方法詳解

    MybatisPlus開啟二級(jí)緩存的方法詳解

    這篇文章主要介紹了MybatisPlus開啟二級(jí)緩存的方法詳解,二級(jí)緩存是基于mapper文件的namespace級(jí)別,也就是說多個(gè)sqlSession可以共享一個(gè)mapper中的二級(jí)緩存區(qū)域,需要的朋友可以參考下
    2023-11-11
  • 全面分析Java文件上傳

    全面分析Java文件上傳

    本片文章給大家詳細(xì)分析了Java文件上傳的相關(guān)知識(shí)點(diǎn),以及相關(guān)代碼做了詳細(xì)分析,有興趣的朋友學(xué)習(xí)下。
    2018-02-02
  • 解決java.lang.NullPointerException報(bào)錯(cuò)以及分析出現(xiàn)的幾種原因

    解決java.lang.NullPointerException報(bào)錯(cuò)以及分析出現(xiàn)的幾種原因

    這篇文章介紹了解決java.lang.NullPointerException報(bào)錯(cuò)的方法,以及分析出現(xiàn)的幾種原因。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • springboot 整合 nacos 配置實(shí)現(xiàn)多個(gè)環(huán)境不同配置

    springboot 整合 nacos 配置實(shí)現(xiàn)多個(gè)環(huán)境不同配置

    本文介紹了Nacos配置中心的優(yōu)勢,包括與Apollo的性能對(duì)比,Nacos服務(wù)端的安裝與配置,以及如何在SpringBoot項(xiàng)目中集成Nacos進(jìn)行多環(huán)境配置,提供了詳細(xì)的步驟,包括下載、安裝、配置中心的創(chuàng)建和項(xiàng)目集成,旨在幫助開發(fā)者更好地使用Nacos進(jìn)行項(xiàng)目配置管理
    2024-09-09
  • Java Runtime類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java Runtime類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Runtime類封裝了運(yùn)行時(shí)的環(huán)境。每個(gè) Java 應(yīng)用程序都有一個(gè) Runtime 類實(shí)例,使應(yīng)用程序能夠與其運(yùn)行的環(huán)境相連接。下面通過本文給大家分享Java Runtime類詳解,需要的朋友參考下吧
    2017-04-04
  • 解決Spring或SpringBoot開啟事務(wù)以后無法返回自增主鍵的問題

    解決Spring或SpringBoot開啟事務(wù)以后無法返回自增主鍵的問題

    這篇文章主要介紹了解決Spring或SpringBoot開啟事務(wù)以后無法返回自增主鍵的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • mybatis-plus的SafetyEncryptProcessor安全加密處理示例解析

    mybatis-plus的SafetyEncryptProcessor安全加密處理示例解析

    這篇文章主要為大家介紹了mybatis-plus的SafetyEncryptProcessor安全加密處理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論

比如县| 鄂托克前旗| 同德县| SHOW| 木兰县| 克东县| 靖安县| 大悟县| 大冶市| 桃源县| 祁阳县| 梁平县| 刚察县| 元朗区| 秀山| 红桥区| 滦南县| 弥渡县| 泽库县| 武穴市| 依兰县| 西和县| 金川县| 天台县| 河曲县| 张家口市| 黔西| 岑溪市| 通化市| 谢通门县| 会理县| 建平县| 日喀则市| 乐至县| 新民市| 东莞市| 太原市| 揭西县| 容城县| 石城县| 邛崃市|