日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
CyclicBarrier:人齊了,老司機就發(fā)車了!

上一篇咱講了 CountDownLatch 可以解決多個線程同步的問題,相比于 join 來說它的應用范圍更廣,不僅可以應用在線程上,還可以應用在線程池上。然而 CountDownLatch 卻是一次性的計數(shù)器,以王者農(nóng)藥來說,咱們不可能一場團戰(zhàn)就決定比賽的輸贏,所以在某些場景下,咱們是需要重復使用某個等待功能的,這就是我們今天要介紹的另一個主角——CyclicBarrier。

創(chuàng)新互聯(lián)主要從事網(wǎng)站設計、網(wǎng)站建設、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務洛浦,十年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:13518219792

CyclicBarrier

CyclicBarrier 翻譯為中文是循環(huán)(Cyclic)柵欄(Barrier)的意思,它的大概含義是實現(xiàn)一個可循環(huán)利用的屏障。

CyclicBarrier 作用是讓一組線程相互等待,當達到一個共同點時,所有之前等待的線程再繼續(xù)執(zhí)行,且 CyclicBarrier 功能可重復使用。

舉個栗子

比如磊哥要坐班車回老家,因為中途不允許上、下乘客,所以營運的公司為了收益最大化,就會等人滿之后再發(fā)車。像這種等人坐滿就發(fā)一班車的場景,就是 CyclicBarrier 所擅長的,因為它可以重復使用(不像 CountDownLatch 那樣只能用一次)。

CyclicBarrier VS CountDownLatch

CountDownLatch:一個或者多個線程,等待另外 N 個線程完成某個事情之后才能執(zhí)行。

CountDownLatch 就像玩王者農(nóng)藥開局的加載一樣,所有人要等待其他人都加載 100% 之后才能開始游戲。

CyclicBrrier:N 個線程相互等待,直到有足夠數(shù)量的線程都到達屏障點之后,之前等待的線程就可以繼續(xù)執(zhí)行了。

CyclicBrrier 就像老司機開車一樣,如果車上還有空余的座位,那么所有人都得等著,直到座位被坐滿之后,老司機才會發(fā)車。

CyclicBarrier使用

 
 
 
 
  1. import java.util.Date;
  2. import java.util.Random;
  3. import java.util.concurrent.*;
  4. public class CyclicBarrierExample {
  5.     public static void main(String[] args) {
  6.         // 創(chuàng)建 CyclicBarrier
  7.         final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
  8.             @Override
  9.             public void run() {
  10.                 System.out.println("人滿了,準備發(fā)車:" + new Date());
  11.             }
  12.         });
  13.         
  14.         // 線程調(diào)用的任務
  15.         Runnable runnable = new Runnable() {
  16.             @Override
  17.             public void run() {
  18.                 // 生成隨機數(shù) 1-3
  19.                 int randomNumber = new Random().nextInt(3) + 1;
  20.                 // 進入任務
  21.                 System.out.println(String.format("我是:%s 再走:%d 秒就到車站了,現(xiàn)在時間:%s",
  22.                         Thread.currentThread().getName(), randomNumber, new Date()));
  23.                 try {
  24.                     // 模擬執(zhí)行
  25.                     TimeUnit.SECONDS.sleep(randomNumber);
  26.                     // 調(diào)用 CyclicBarrier
  27.                     cyclicBarrier.await();
  28.                     // 任務執(zhí)行
  29.                     System.out.println(String.format("線程:%s 上車,時間:%s",
  30.                             Thread.currentThread().getName(), new Date()));
  31.                 } catch (InterruptedException e) {
  32.                     e.printStackTrace();
  33.                 } catch (BrokenBarrierException e) {
  34.                     e.printStackTrace();
  35.                 }
  36.             }
  37.         };
  38.         // 創(chuàng)建線程池
  39.         ExecutorService threadPool = Executors.newFixedThreadPool(10);
  40.         // 執(zhí)行任務 1
  41.         threadPool.submit(runnable);
  42.         // 執(zhí)行任務 2
  43.         threadPool.submit(runnable);
  44.         // 執(zhí)行任務 3
  45.         threadPool.submit(runnable);
  46.         // 執(zhí)行任務 4
  47.         threadPool.submit(runnable);
  48.         // 等待所有任務執(zhí)行完終止線程池
  49.         threadPool.shutdown();
  50.     }
  51. }

以上代碼執(zhí)行結果如下:

從上述結果可以看出:當 CyclicBarrier 的計數(shù)器設置為 2 時,線程 2 和 線程 3 都到屏障點之后,老司機才會發(fā)第一波車,再 2s 之后,線程 1 和線程 4 也同時進入了屏障點,這時候老司機又可以再發(fā)一波車了。

實現(xiàn)原理

我們先來看下 CyclicBarrier 的類圖:

由上圖可知 CyclicBarrier 是基于獨占鎖 ReentrantLock 實現(xiàn)的,其底層也是基于 AQS 的。

在 CyclicBarrier 類的內(nèi)部有一個計數(shù)器 count,當 count 不為 0 時,每個線程在到達屏障點會先調(diào)用 await 方法將自己阻塞,此時計數(shù)器會減 1,直到計數(shù)器減為 0 的時候,所有因調(diào)用 await 方法而被阻塞的線程就會被喚醒繼續(xù)執(zhí)行。當 count 計數(shù)器變成 0 之后,就會進入下一輪阻塞,此時 parties(parties 是在 new CyclicBarrier(parties) 時設置的值)會將它的值賦值給 count 從而實現(xiàn)復用。

常用方法

CyclicBarrier(parties):初始化相互等待的線程數(shù)量的構造方法。

CyclicBarrier(parties,Runnable barrierAction):初始化相互等待的線程數(shù)量以及屏障線程的構造方法,當 CyclicBarrier 的計數(shù)器變?yōu)?0 時,會執(zhí)行 barrierAction 構造方法。

getParties():獲取 CyclicBarrier 打開屏障的線程數(shù)量,也稱為方數(shù)。

getNumberWaiting():獲取正在CyclicBarrier上等待的線程數(shù)量。

await():在 CyclicBarrier 上進行阻塞等待,直到發(fā)生以下情形之一:在 CyclicBarrier 上等待的線程數(shù)量達到 parties,則所有線程被釋放,繼續(xù)執(zhí)行;

  • 當前線程被中斷,則拋出 InterruptedException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他等待的線程被中斷,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他等待的線程超時,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他線程調(diào)用 CyclicBarrier.reset() 方法,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行。

await(timeout,TimeUnit):在CyclicBarrier上進行限時的阻塞等待,直到發(fā)生以下情形之一:

  • 在 CyclicBarrier 上等待的線程數(shù)量達到 parties,則所有線程被釋放,繼續(xù)執(zhí)行;
  • 當前線程被中斷,則拋出 InterruptedException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 當前線程等待超時,則拋出 TimeoutException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他等待的線程被中斷,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他等待的線程超時,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行;
  • 其他線程調(diào)用 CyclicBarrier.reset() 方法,則當前線程拋出 BrokenBarrierException 異常,并停止等待,繼續(xù)執(zhí)行。

isBroken():獲取是否破損標志位 broken 的值,此值有以下幾種情況:

  • CyclicBarrier 初始化時,broken=false,表示屏障未破損;
  • 如果正在等待的線程被中斷,則 broken=true,表示屏障破損;
  • 如果正在等待的線程超時,則 broken=true,表示屏障破損;
  • 如果有線程調(diào)用 CyclicBarrier.reset() 方法,則 broken=false,表示屏障回到未破損狀態(tài)。

reset():使得CyclicBarrier回歸初始狀態(tài),直觀來看它做了兩件事:

  • 如果有正在等待的線程,則會拋出 BrokenBarrierException 異常,且這些線程停止等待,繼續(xù)執(zhí)行。
  • 將是否破損標志位 broken 置為 false。

總結

CyclicBrrier 是通過獨占鎖 ReentrantLock 實現(xiàn)計數(shù)器的原子性更新的,CyclicBrrier 最常用的是 await() 方法,使用此方法會將計數(shù)器 -1,并判斷當前的計數(shù)器是否為 0,如果不為 0 就會阻塞等待,并計時器為 0 之后,才能繼續(xù)執(zhí)行剩余任務。CyclicBrrier 相比于 CountDownLatch 來說,它的優(yōu)勢在于可以重復使用。

參考 & 鳴謝

  • blog.csdn.net/qq_39241239/article/details/87030142
  • blog.csdn.net/zzg1229059735/article/details/61191679
  • www.cnblogs.com/yaochunhui/p/13494689.html

分享文章:CyclicBarrier:人齊了,老司機就發(fā)車了!
URL標題:http://www.dlmjj.cn/article/cdhihdh.html