當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Java Java.util.concurrent.CyclicBarrier用法及代碼示例


CyclicBarrier 用於使線程相互等待。當不同的線程處理一部分計算,當所有線程都完成執行後,需要在父線程中合並結果時使用。換句話說,當多個線程執行不同的子任務並且需要組合這些子任務的輸出以形成最終輸出時,使用CyclicBarrier。執行完成後,線程調用await()方法並等待其他線程到達屏障。一旦所有線程都到達,障礙就會為線程繼續前進提供道路。

Working of CyclicBarrier

CyclicBarriers 在java.util.concurrent 包中定義。首先創建 CyclicBarriers 的新實例,指定屏障應等待的線程數。

CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads);

每個線程都會進行一些計算,並在完成執行後調用 await() 方法,如下所示:

public void run()
{
    // thread does the computation
    newBarrier.await();
}

CyclicBarrier 的工作原理:


一旦調用 await() 的線程數等於線程數,屏障就會為等待線程提供一條道路。 CyclicBarrier 也可以通過所有線程到達屏障後執行的某些操作來初始化。此操作可以組合/利用在屏障中等待的各個線程的計算結果。

Runnable action = ... 
//action to be performed when all threads reach the barrier;
CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads, action);

CyclicBarrier的重要方法:

  1. getParties:返回觸發此障礙所需的參與方數量。
    Syntax:
    public int getParties()

    返回:
    跨越這一障礙所需的參與方數量

  2. reset:將屏障重置為其初始狀態。
    Syntax:
    public void reset()

    返回:
    void 但將屏障重置為其初始狀態。如果任何一方當前在屏障處等待,他們將返回 BrokenBarrierException。

  3. isBroken:查詢此屏障是否處於損壞狀態。
    Syntax:
    public boolean isBroken()

    返回:
    如果一方或多方由於自構建或上次重置以來的中斷或超時而突破此障礙,或者由於異常導致障礙操作失敗,則為 true;否則為假。

  4. getNumberWaiting:返回當前在屏障處等待的各方數量。
    Syntax:
    public int getNumberWaiting()

    返回:
    await()中當前被阻止的政黨數量

  5. await:等待所有各方都在此屏障上調用等待。
    Syntax:
    public int await() throws InterruptedException, BrokenBarrierException

    返回:
    當前線程的到達索引,其中索引getParties() - 1 表示第一個到達,0 表示最後一個到達。

  6. await:等待直到所有各方都在此屏障上調用await,或者指定的等待時間過去。
    Syntax:
    public int await(long timeout, TimeUnit unit) 
    throws InterruptedException,
    BrokenBarrierException, TimeoutException

    返回:
    當前線程的到達索引,其中索引getParties() - 1表示第一個到達,0表示最後一個到達


//JAVA program to demonstrate execution on Cyclic Barrier 
  
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.TimeoutException; 
import java.util.concurrent.BrokenBarrierException; 
import java.util.concurrent.CyclicBarrier; 
  
class Computation1 implements Runnable 
{ 
    public static int product = 0; 
    public void run() 
    { 
        product = 2 * 3; 
        try
        { 
            Tester.newBarrier.await(); 
        }  
        catch (InterruptedException | BrokenBarrierException e)  
        { 
            e.printStackTrace(); 
        } 
    } 
} 
  
class Computation2 implements Runnable 
{ 
    public static int sum = 0; 
    public void run() 
    { 
        // check if newBarrier is broken or not 
        System.out.println("Is the barrier broken? - " + Tester.newBarrier.isBroken()); 
        sum = 10 + 20; 
        try
        { 
            Tester.newBarrier.await(3000, TimeUnit.MILLISECONDS); 
          
            // number of parties waiting at the barrier 
            System.out.println("Number of parties waiting at the barrier "+ 
            "at this point = " + Tester.newBarrier.getNumberWaiting()); 
        }  
        catch (InterruptedException | BrokenBarrierException e)  
        { 
            e.printStackTrace(); 
        }  
        catch (TimeoutException e)  
        { 
            e.printStackTrace(); 
        } 
    } 
} 
  
  
public class Tester implements Runnable 
{ 
    public static CyclicBarrier newBarrier = new CyclicBarrier(3); 
      
    public static void main(String[] args) 
    { 
        // parent thread 
        Tester test = new Tester(); 
          
        Thread t1 = new Thread(test); 
        t1.start(); 
    } 
    public void run() 
    { 
        System.out.println("Number of parties required to trip the barrier = "+ 
        newBarrier.getParties()); 
        System.out.println("Sum of product and sum = " + (Computation1.product +  
        Computation2.sum)); 
          
        // objects on which the child thread has to run 
        Computation1 comp1 = new Computation1(); 
        Computation2 comp2 = new Computation2(); 
          
        // creation of child thread 
        Thread t1 = new Thread(comp1); 
        Thread t2 = new Thread(comp2); 
          
        // moving child thread to runnable state 
        t1.start(); 
        t2.start(); 
  
        try
        { 
            Tester.newBarrier.await(); 
        }  
        catch (InterruptedException | BrokenBarrierException e)  
        { 
            e.printStackTrace(); 
        } 
          
        // barrier breaks as the number of thread waiting for the barrier 
        // at this point = 3 
        System.out.println("Sum of product and sum = " + (Computation1.product +  
        Computation2.sum)); 
                  
        // Resetting the newBarrier 
        newBarrier.reset(); 
        System.out.println("Barrier reset successful"); 
    } 
} 

輸出:

<Number of parties required to trip the barrier = 3
Sum of product and sum = 0
Is the barrier broken? - false
Number of parties waiting at the barrier at this point = 0
Sum of product and sum = 36
Barrier reset successful

解釋:(sum + Product) = 0 的值打印在控製台上,因為子線程還沒有運行來設置 sum 和 Product 變量的值。接下來,(sum + Product) = 36 會打印在控製台上,因為子線程運行時設置了 sum 和 Product 的值。此外,屏障上等待的線程數量達到了3,因此屏障允許所有線程通過,最終打印出36。 “此時在屏障處等待的各方數量”的值 = 0,因為所有三個線程都已調用 await() 方法,因此屏障不再處於活動狀態。最後newBarrier被重置,可以再次使用。

BrokenBarrierException

當任何等待線程離開屏障時,屏障就會中斷。當一個或多個等待線程被中斷或等待時間完成時,會發生這種情況,因為線程調用了超時的 await() 方法,如下所示:

newBarrier.await(1000, TimeUnit.MILLISECONDS);
// thread calling this await() 
// methods waits for only 1000 milliseconds.

當屏障由於多個參與線程之一而破壞時,所有其他線程的 await() 方法將引發 BrokenThreadException。而已經在屏障中等待的線程則終止其 await() 調用。

Difference between a CyclicBarrier and a CountDownLatch

  • CountDownLatch 在程序中隻能使用一次(直到計數達到 0)。
  • 一旦屏障中的所有線程被釋放,CyclicBarrier 就可以一次又一次地使用。

參考:Oracle



相關用法


注:本文由純淨天空篩選整理自佚名大神的英文原創作品 Java.util.concurrent.CyclicBarrier in Java。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。