Java的循環屏障-CyclicBarrier(譯)

新書Java併發編程系統與模型已上線,歡迎拜讀。

前言

      barrier(屏障)與互斥量,讀寫鎖,自旋鎖不一樣,它不是用來保護臨界區的。相反,它跟條件變量同樣,是用來協同多線程一塊兒工做的。
條件變量是多線程間傳遞狀態的改變來達到協同工做的效果。屏障是多線程各自作本身的工做,若是某一線程完成了工做,就等待在屏障那裏,直到其餘線程的工做都完成了,再一塊兒作別的事。舉個通俗的例子:
      1.對於條件變量。在接力賽跑裏,1號隊員開始跑的時候,2,3,4號隊員都站着不動,直到1號隊員跑完一圈,把接力棒給2號隊員,2號隊員收到接力棒後就能夠跑了,跑完再給3號隊員。這裏這個接力棒就至關於條件變量,條件知足後就能夠由下一個隊員(線程)跑。
      2.對於屏障:在百米賽跑裏,比賽沒開始以前,每一個運動員都在賽場上自由活動,有的熱身,有的喝水,有的跟教練談論。比賽快開始時,準備完畢的運動員就預備在起跑線上,若是有個運動員還沒準備完(除去特殊狀況),他們就一直等,直到運動員都在起跑線上,裁判喊口號後再開始跑。這裏的起跑線就是屏障,作完準備工做的運動員都等在起跑線,直到其餘運動員也把準備工做作完。javascript

      java.util.concurrent.CyclicBarrier類是一個同步機制。它能夠經過一些算法來同步線程處理的過程。換言之,就是全部的線程必須等待對方,直到全部的線程到達屏障,而後繼續運行。下面這個圖能夠說明:
java


                                                兩個線程等待循環屏障

      兩個線程經過調用CyclicBarrier的 await() 相互等待對方,一旦全部的線程都在CyclicBarrier中等待,而後全部的線程一塊兒釋放而後繼續執行。算法

建立循環屏障

      當你要建立CyclicBarrier的時候必須指定在釋放他們前有多少個線程等待,下面是一個例子:編程

CyclicBarrier barrier = new CyclicBarrier(2);複製代碼

在CyclicBarrier等待

      下面是在CyclicBarrier處等待:多線程

barrier.await();複製代碼

      你也能夠指線程等待的超時時間,當等待超時的時候,線程依然會被釋放。即便並非全部的線程都開始在CyclicBarrier等待。下面這行代碼指定超時時間:併發

barrier.await(10, TimeUnit.SECONDS);複製代碼

      全部線程在CyclicBarrier等待,是指:
       • 最後一個線程到達(調用await方法)this

       • 一個線程被被另一個線程中斷(另一個線程調用了這個現場的interrupt()方法)spa

       • 其中一個等待的線程被中斷線程

       • 其中一個等待的線程超時code

       • 一個外部的線程調用了yclicBarrier.reset()方法。

CyclicBarrier Action

      CyclicBarrier 支持一個Runnable屏障動做。當最後一個線程到達的時候,這個Runable對象就能夠被執行。你須要將這個Runable屏障動做放置在他的構造器中,就像這樣:

Runnable      barrierAction = ... ;
CyclicBarrier barrier       = new CyclicBarrier(2, barrierAction);複製代碼

下面這個例子說明了如何使用CyclicBarrier:

Runnable barrier1Action = new Runnable() {
    public void run() {
        System.out.println("BarrierAction 1 executed ");
    }
};
Runnable barrier2Action = new Runnable() {
    public void run() {
        System.out.println("BarrierAction 2 executed ");
    }
};

CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);

CyclicBarrierRunnable barrierRunnable1 =
        new CyclicBarrierRunnable(barrier1, barrier2);

CyclicBarrierRunnable barrierRunnable2 =
        new CyclicBarrierRunnable(barrier1, barrier2);

new Thread(barrierRunnable1).start();
new Thread(barrierRunnable2).start();
Here is the CyclicBarrierRunnable class:複製代碼

      下面是CyclicBarrierRunnable類:

public class CyclicBarrierRunnable implements Runnable{

    CyclicBarrier barrier1 = null;
    CyclicBarrier barrier2 = null;

    public CyclicBarrierRunnable(
            CyclicBarrier barrier1,
            CyclicBarrier barrier2) {

        this.barrier1 = barrier1;
        this.barrier2 = barrier2;
    }

    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() +
                                " waiting at barrier 1");
            this.barrier1.await();

            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() +
                                " waiting at barrier 2");
            this.barrier2.await();

            System.out.println(Thread.currentThread().getName() +
                                " done!");

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}複製代碼

      下面是控制檯的輸出。可是要注意有時候輸出的順序會發生變化,有時候是Thread-0先打印,有時候是Thread-1先打印。

Thread-0 waiting at barrier 1
Thread-1 waiting at barrier 1
BarrierAction 1 executed
Thread-1 waiting at barrier 2
Thread-0 waiting at barrier 2
BarrierAction 2 executed
Thread-0 done!
Thread-1 done!複製代碼

小廣告

新書《Java併發編程系統與模型》目前已經寫完一部分。可是實際上說實話,並不知道讀者們對java併發系統有哪些比較關心的,並且閉門造車實在是太累,寫出來怕沒人看。因此我放在這裏徵求你們的意見。你們能夠直接在評論裏提問或者但願做者重點描寫哪一部份內容,我好有針對性的寫。

相關文章
相關標籤/搜索