1. 程式人生 > >【執行緒知識點】-- 柵欄:CyclicBarrier

【執行緒知識點】-- 柵欄:CyclicBarrier

1快速瞭解

首先看下JDK中的介紹:

/**
 * A synchronization aid that allows a set of threads to all wait for
 * each other to reach a common barrier point.  CyclicBarriers are
 * useful in programs involving a fixed sized party of threads that
 * must occasionally wait for each other. The barrier is called
 * <em>cyclic</em> because it can be re-used after the waiting threads
 * are released.

CyclicBarrier是一個同步工具類,它允許一組執行緒在到達某個柵欄點(common barrier point)互相等待,發生阻塞,直到最後一個執行緒到達柵欄點,柵欄才會開啟,處於阻塞狀態的執行緒恢復繼續執行.它非常適用於一組執行緒之間必需經常互相等待的情況。CyclicBarrier字面理解是迴圈的柵欄,之所以稱之為迴圈的是因為在等待執行緒釋放後,該柵欄還可以複用。

納尼?沒看懂?那這樣,說個實際場景你必然就知道這東東是做啥的了得意

LOL玩過吧,是不是要十個人全部準備載入100%之後才能進遊戲,要是有個人載入特別慢,那剩下的人就得等著~

明白了?嘿嘿,程式碼實現一下,你再看看,看不懂就去下載LOL吧~  //我亞索賊溜~

public class CyclicBarrierTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(5);
        CyclicBarrier barrier = new CyclicBarrier(5);//引數為阻塞執行緒 
        List<String> nameList = new ArrayList<>();
        Collections.addAll(nameList, "-----盲僧-----"
, "-----劍聖-----", "-----卡莎-----", "-----風男-----", "-----蠢劫-----","-----大嘴-----","-----蛤蟆-----"); for (int i = 0; i < 5; i++) { service.execute(new Player("玩家" + nameList.get(0), barrier)); nameList.remove(0); } service.shutdown(); } } class Player implements Runnable { private final String name; private final CyclicBarrier barrier; public Player(String name, CyclicBarrier barrier) { this.name = name; this.barrier = barrier; } public void run() { try { TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3))); System.out.println(name + "已準備,等待其他玩家準備..."); barrier.await(); TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3))); System.out.println(name + "已加入遊戲"); } catch (InterruptedException e) { System.out.println(name + "離開遊戲"); } catch (BrokenBarrierException e) { System.out.println(name + "離開遊戲"); } } }

這是列印結果:

玩家-----蠢劫-----已準備,等待其他玩家準備...
玩家-----風男-----已準備,等待其他玩家準備...
玩家-----盲僧-----已準備,等待其他玩家準備...
玩家-----卡莎-----已準備,等待其他玩家準備...
玩家-----劍聖-----已準備,等待其他玩家準備...
玩家-----卡莎-----已加入遊戲
玩家-----劍聖-----已加入遊戲
玩家-----盲僧-----已加入遊戲
玩家-----蠢劫-----已加入遊戲
玩家-----風男-----已加入遊戲

怎麼樣~

這個類有兩個構造方法:

public CyclicBarrier(int parties) 
public CyclicBarrier(int parties, Runnable barrierAction)

引數parties指定執行緒數量,當指定的執行緒值都到達柵欄點時,柵欄開啟,執行緒恢復。

需要注意的是,當指定的執行緒數量大於啟動的執行緒數量,比如修改上例中的程式碼,只啟動4個執行緒,那麼所有的執行緒將一直處於等待狀態。瞅下程式碼~

for (int i = 0; i < 4; i++) { //上面示例中是5,我們這裡改成了4
            service.execute(new Player("玩家" + nameList.get(0), barrier));
            nameList.remove(0);
}

再看下列印結果:發現只有四個玩家準備了,沒有人進入遊戲。而且我們的程式並沒有結束(shutDown並沒有執行)


第二種情況是指定的執行緒數量小於啟動的執行緒,上例程式碼,啟動6個執行緒,那麼當第5個執行緒到達柵欄點時,那麼這5個執行緒就會恢復繼續執行,而第6個執行緒將一直處於阻塞狀態。大家可以自行修改程式碼驗證一下~ 

CyclicBarrier還提供一個更高階的建構函式CyclicBarrier(int parties, Runnable barrierAction),用於線上程到達屏障時,優先執行barrierAction,方便處理更復雜的業務場景。我們 把上面的CyclicBarrier建立程式碼修改成如下~

CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("已經到達柵欄點~");
            }
        });

列印結果是這樣的:

玩家-----卡莎-----已準備,等待其他玩家準備...
玩家-----蠢劫-----已準備,等待其他玩家準備...
玩家-----劍聖-----已準備,等待其他玩家準備...
玩家-----盲僧-----已準備,等待其他玩家準備...
玩家-----風男-----已準備,等待其他玩家準備...
已經到達柵欄點~
玩家-----劍聖-----已加入遊戲
玩家-----卡莎-----已加入遊戲
玩家-----風男-----已加入遊戲
玩家-----盲僧-----已加入遊戲
玩家-----蠢劫-----已加入遊戲

2常用方法介紹

await()

Waits until all parties have invoked await on this barrier.

呼叫該方法會使當前執行緒在柵欄點發生阻塞,直到指定的執行緒數量都達到柵欄點時恢復執行

await(long timeout, TimeUnit unit)

Waits until all parties have invoked await on this barrier, or the specified waiting time elapses.

類似於await(),增加了超時時間引數。 

參考如下程式碼:

public void run() {
    try {
        TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
        System.out.println(name + "已準備,等待其他玩家準備...");
        barrier.await(200, TimeUnit.MILLISECONDS);
        TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
        System.out.println(name + "已加入遊戲");
    } catch (InterruptedException e) {
        System.out.println(name + "離開遊戲");
    } catch (BrokenBarrierException e) {
        System.out.println(name + "離開遊戲");
    } catch (TimeoutException e) {
        System.out.println(name + "連線超時");
    }
}

結果如下:

玩家-----劍聖-----已準備,等待其他玩家準備...
玩家-----卡莎-----已準備,等待其他玩家準備...
玩家-----劍聖-----連線超時
玩家-----卡莎-----離開遊戲
玩家-----風男-----已準備,等待其他玩家準備...
玩家-----蠢劫-----已準備,等待其他玩家準備...
玩家-----蠢劫-----離開遊戲
玩家-----風男-----離開遊戲
玩家-----盲僧-----已準備,等待其他玩家準備...
玩家-----盲僧-----離開遊戲

上面的程式碼修改了CyclicBarrierTest.java裡面的run()方法,當barrier在等待點出等待超時時,會丟擲TimeoutException異常,同時,位於該barrier上的其他執行緒也將毀丟擲BrokenBarrierException異常。這裡說明,barrier上的執行緒要麼同時成功要麼同時失敗,不存在部分成功部分失敗的場景。

getNumberWaiting()

Returns the number of parties currently waiting at the barrier.

返回當前在柵欄處等待的參與者數目。此方法主要用於除錯和斷言。

getParties()

Returns the number of parties required to trip this barrier.

該方法可以獲得建構函式中指定的需要在柵欄點阻塞的執行緒數量

isBroken()

Queries if this barrier is in a broken state

查詢此柵欄是否處於損壞狀態。

reset()

Resets the barrier to its initial state.

將barrier重置為其初始狀態。如果所有參與者目前都在屏障處等待,則它們將返回,同時丟擲一個 BrokenBarrierException

3應用場景

CyclicBarrier可以用於多執行緒計算資料,最後合併計算結果的應用場景。比如我們用一個Excel儲存了使用者所有銀行流水,每個Sheet儲存一個帳戶近一年的每筆銀行流水,現在需要統計使用者的日均銀行流水,先用多執行緒處理每個sheet裡的銀行流水,都執行完之後,得到每個sheet的日均銀行流水,最後,再用barrierAction用這些執行緒的計算結果,計算出整個Excel的日均銀行流水

參考:

https://blog.csdn.net/yin380697242/article/details/53313622

相關推薦

執行知識點-- 柵欄CyclicBarrier

1快速瞭解首先看下JDK中的介紹:/** * A synchronization aid that allows a set of threads to all wait for * each other to reach a common barrier point.

執行知識點--可見性

可見性可見性:一個執行緒對共享變數的修改,能夠及時的被其它執行緒看到。共享變數:如果一個變數在多個執行緒的工作記憶體中都存在副本,那麼這個變數就是這幾個執行緒的共享變數。Java記憶體模型所有的變數都存貯在主記憶體中每個執行緒都擁有自己獨立的工作記憶體,裡邊儲存該執行緒使用到

給初學者的RxJava2.0教程(二)執行控制

前言 上一節教程講解了最基本的RxJava2的使用, 在本節中, 我們將學習RxJava強大的執行緒控制. 正題 還是以之前的例子, 兩根水管: 正常情況下, 上游和下游是工作在同一個執行緒中的, 也就是說上游在哪個執行緒發事件,

執行同步執行同步

  linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數和訊號量。(臨界區) 1)互斥鎖(mutex) {臨界區和互斥量(互斥鎖)的區別https://blog.csdn.net/bandaoyu/article/details/8399809 1. Mu

執行同步臨界區與互斥量

Win32 中關於程序和執行緒的協調工作是由同步機制來完成的,同步機制相當於執行緒間的紅綠燈。 一. 同步和非同步 舉個例子: PostMessage(),是把訊息放到對方的訊息佇列中,然後不管三七二十一,就回到原呼叫點繼續執行,這就是非同步。 SendMessage(),就像呼叫一

執行2Thread的方法

Thread的常用方法 (1).start():啟動執行緒並執行相應的run()方法 (2).run():子執行緒要執行的程式碼放入run()方法中 (3).currentThread():靜態的,調取當前的執行緒 (4).getName():獲取此執行緒的名字 (

Java多執行之JUC包CyclicBarrier原始碼學習筆記

若有不正之處請多多諒解,並歡迎批評指正。 請尊重作者勞動成果,轉載請標明原文連結: CyclicBarrier是java.util.concurrent包中提供的同步工具。通過這個工具我們可以實現n個執行緒相互等待。我們可以通過引數指定達到公共屏障點之後的行為。 先上原始碼:

執行Executors中的newSingleThreadExecutor和newFixedThreadPool(1)的區別

在上一篇【執行緒池】深入理解Executors類時,提到了newSingleThreadExecutor和newFixedThreadPool(1)的區別,查閱了大量資料,自己也做了一些實驗,但是還是有很多不清楚的地方,這篇文章主要是用作討論,如果有大佬有好的回答,拜託請多多

執行執行

#### 一、什麼是執行緒池 > 執行緒池:指在初始化一個多執行緒應用程式過程中建立一個執行緒集合,然後在需要執行新的任務時重用這些執行緒而不是新建一個執行緒, > > 一旦任務已經完成了,執行緒回到池子中並等待下一次分配任務。 #### 二、使用執行緒池的好處 > 1)控制最大並大數。 > > 2)降

2019春招準備22.執行生命週期(主執行和子執行

參考:強烈推薦 https://blog.csdn.net/u013905744/article/details/73741056 run java application: 建立一個java虛擬機器程序,main執行緒和userThread都可以在裡面跑,當沒有執行緒的時候,退出程

JAVA併發包原始碼分析迴圈柵欄CyclicBarrier

一、認識CyclicBarrier 對於CyclicBarrier大多數人感到陌生,其實CyclicBarrier是一種多執行緒併發控制使用工具,和CountDownLatch非常類似,實現執行緒之間的計數等待,也就是說一個執行緒或者多個執行緒等待其他執行緒完

執行sleep() 和 wait() 的區別

https://blog.csdn.net/xyh269/article/details/52613507?utm_source=blogkpcl6   https://blog.csdn.net/lcore/article/details/12221217?utm_source=

執行複習筆記之二執行間的通訊

Object.wait:釋放鎖,當時程式碼不會往下繼續執行,需要等待notify通知,wait(1000)超過1秒自動喚醒 Object.notify:不釋放鎖,需要等到同步程式碼塊執行完畢,如果沒有wait執行緒,notify命令將被忽略。 condition 如果有多個執行緒處於等待

執行程式設計 synchronized全域性鎖和例項鎖的區別

例項鎖 -- 鎖在某一個例項物件上。如果該類是單例,那麼該鎖也具有全域性鎖的概念。                例項鎖對應的就是synchronized關鍵字。全域性鎖 -- 該鎖針對的是類,無論例項多少個物件,那麼執行緒都共享該鎖。                全域性鎖

JAVA基礎24-多執行(四)讀寫鎖,阻塞佇列,執行

一、讀寫鎖   使用步驟 二、阻塞佇列 (BlockingQueue) 提供執行緒安全的佇列訪問方式; 當阻塞佇列進行插入資料時,若佇列滿,則執行緒阻塞,直到佇列非滿的時候 當阻塞佇列取資料時,若佇列為空,則執行緒阻塞直到佇列非空時候。

JAVA基礎23-多執行(二)執行區域性變數和未捕獲異常處理器

一、執行緒區域性變數    線上程中使用共享變數肯定是存在風險。為了規避這個風險,利用同步機制,volatile這些方法都可以。但是也可為每個執行緒分配一個變數。使用ThreadLocal輔助類為各個執行緒提供各自的例項。  ThreadLocal為每個使用

執行 ThreadLocal

       ThreadLocal類提供了執行緒區域性變數。這些變數不同於他們的普通對應物,因為訪問一個變數(通過get或set方法)的每個執行緒都有自己的區域性變數,它獨立於變數的初始化副本。ThreadLocal例項通常是類中的私有靜態欄位,他

執行java之Thread.sleep(long)與object.wait()/object.wait(long)的區別及相關概念梳理

一、Thread.sleep(long)與object.wait()/object.wait(long)的區別 sleep(long)與wait()/wait(long)行為上有些類似,主要區別如下

方格取數執行DP&傳紙條執行DP

題目: 設有N*N的方格圖(N<=10,我們將其中的某些方格中填入正整數,而其他的方格中則放入數字0。如下圖所示(見樣例): 某人從圖的左上角的A 點出發,可以向下行走,也可以向右走,直到到達右下角的B點。在走過的路上,他可以取走方格中的數(取走後的方格中將變為數字0)。

執行的同步與互斥 (互斥量 條件變數 訊號量)生產者與消費者模型

執行緒 執行緒是程序中的一個獨立的執行流,由環境(包括暫存器集和程式計數器)和一系列要執行的置零組成。所有程序至少有一個執行緒組成,多執行緒的程序包括多個執行緒,所有執行緒共享為程序分配的公共地址空間,所以文字段(Text Segment)和資料段(Datan