モジュール java.base
パッケージ java.util.concurrent

クラスCyclicBarrier


  • public class CyclicBarrier
    extends Object
    スレッド・セットのそれぞれが共通のバリアー・ポイントに達するまで待機することを可能にする同期化支援機能です。 CyclicBarrierは、相互に待機することが必要になることがある、固定サイズのスレッド・パーティが関係するプログラムで有用です。 バリアーは、待機中のスレッドが解放されたあとに再利用できるため、cyclic (循環式)と呼ばれます。

    CyclicBarrierは、オプションのRunnableコマンドをサポートします。これは、パーティ内の最後のスレッドが到着した後で、スレッドが解放される前にバリアー・ポイントごとに1回実行されます。 このバリアー・アクションは、いずれかのパーティが処理を続行する前に共有状態を更新するために役立ちます。

    使用例: 次に、並列分解設計でのバリアーの使用例を示します。

     
     class Solver {
       final int N;
       final float[][] data;
       final CyclicBarrier barrier;
    
       class Worker implements Runnable {
         int myRow;
         Worker(int row) { myRow = row; }
         public void run() {
           while (!done()) {
             processRow(myRow);
    
             try {
               barrier.await();
             } catch (InterruptedException ex) {
               return;
             } catch (BrokenBarrierException ex) {
               return;
             }
           }
         }
       }
    
       public Solver(float[][] matrix) {
         data = matrix;
         N = matrix.length;
         Runnable barrierAction = () -> mergeRows(...);
         barrier = new CyclicBarrier(N, barrierAction);
    
         List<Thread> threads = new ArrayList<>(N);
         for (int i = 0; i < N; i++) {
           Thread thread = new Thread(new Worker(i));
           threads.add(thread);
           thread.start();
         }
    
         // wait until done
         for (Thread thread : threads)
           thread.join();
       }
     }
    ここで、各ワーカー・スレッドは行列の1行を処理して、すべての行が処理されるまでバリアーで待機します。 すべての行が処理されると、指定されたRunnableバリアー・アクションが実行されて、行をマージします。 処理結果が成功したとマージャが判定すると、done()trueを返して、各ワーカーが終了します。

    バリアー・アクションがその実行時に、パーティが中断していなくてもよい場合、パーティ内のいずれかのスレッドは解放されるときに、そのアクションを実行できます。 これを容易にするため、await()の各呼出しは、バリアーの位置でそのスレッドの到着インデックスを返します。 その後、バリアー・アクションを実行するスレッドを選択できます。次に例を示します。

     
     if (barrier.await() == 0) {
       // log the completion of this iteration
     }

    CyclicBarrierは、失敗した同期化の試みに対して全か無かの切断モデルを使用します。割り込み、失敗、またはタイム・アウトのためにスレッドが早くバリアー・ポイントを超えた場合は、そのバリアー・ポイントで待機しているその他のすべてのスレッドもBrokenBarrierExceptionをスローして異常にバリアー・ポイントを越えてしまいます。それらのスレッドもほぼ同時に割り込まれた場合はInterruptedExceptionをスローします。

    メモリー整合性効果: await()を呼び出す前のスレッド内のアクションは、バリアー・アクションの一部であるアクションよりも前に発生し、一方それは、ほかのスレッド内の対応するawait()からの正常な復帰に続くアクションよりも前に発生します。

    導入されたバージョン:
    1.5
    関連項目:
    CountDownLatch
    • コンストラクタのサマリー

      コンストラクタ 
      コンストラクタ 説明
      CyclicBarrier​(int parties)
      指定された数のパーティ(スレッド)が待機状態にある場合にトリップする、新しいCyclicBarrierを作成します。バリアーのトリップ時に、定義済みのアクションは実行されません。
      CyclicBarrier​(int parties, Runnable barrierAction)
      指定された数のパーティ(スレッド)が待機状態にある場合にトリップする、新しいCyclicBarrierを作成します。バリアーのトリップ時に、指定されたバリアー・アクションが、最後にバリアーに入ったスレッドにより実行されます。
    • コンストラクタの詳細

      • CyclicBarrier

        public CyclicBarrier​(int parties,
                             Runnable barrierAction)
        指定された数のパーティ(スレッド)が待機状態にある場合にトリップする、新しいCyclicBarrierを作成します。バリアーのトリップ時に、指定されたバリアー・アクションが、最後にバリアーに入ったスレッドにより実行されます。
        パラメータ:
        parties - バリアーがトリップする前にawait()を呼び出す必要があるスレッドの数
        barrierAction - バリアーがトリップされたときに実行するコマンド。アクションが存在しない場合はnull
        例外:
        IllegalArgumentException - partiesが1より小さい場合
      • CyclicBarrier

        public CyclicBarrier​(int parties)
        指定された数のパーティ(スレッド)が待機状態にある場合にトリップする、新しいCyclicBarrierを作成します。バリアーのトリップ時に、定義済みのアクションは実行されません。
        パラメータ:
        parties - バリアーがトリップする前にawait()を呼び出す必要があるスレッドの数
        例外:
        IllegalArgumentException - partiesが1より小さい場合
    • メソッドの詳細

      • getParties

        public int getParties()
        このバリアーのトリップに必要なパーティの数を返します。
        戻り値:
        このバリアーのトリップに必要なパーティの数
      • await

        public int await()
                  throws InterruptedException,
                         BrokenBarrierException
        すべてのパーティがこのバリアーでawaitを呼び出すまで待機します。

        現在のスレッドが、到着する最後のスレッドではない場合、スレッドのスケジューリングに関して無効になり、次のいずれかが起きるまで待機します。

        • 最後のスレッドが到着する
        • ほかのスレッドが現在のスレッドに割り込みを行う。または
        • 別のスレッドが待機中の他のスレッドの1つに割り込みを行う
        • バリアーの待機中にほかのスレッドがタイム・アウトする
        • ほかのスレッドがこのバリアーに対してreset()を呼び出す。

        現在のスレッドで、

        • このメソッドへのエントリ上で設定された割込みステータスが保持されるか、
        • 待機中に割り込みが発生した場合
        InterruptedExceptionがスローされ、現在のスレッドの割込みステータスがクリアされます。

        いずれかのスレッドが待機中にバリアーでreset()が実行されるか、awaitの呼出し時、またはいずれかのスレッドが待機中にバリアーが破壊された場合、BrokenBarrierExceptionがスローされます。

        待機中のいずれかのスレッドで割り込みが発生した場合、待機中の他のスレッドがすべてBrokenBarrierExceptionをスローし、バリアーが故障状態に置かれます。

        現在のスレッドが到着する最後のスレッドであり、コンストラクタ内でnullではないバリアー・アクションが指定される場合、現在のスレッドはアクションを実行してから、ほかのスレッドの続行を許可します。 バリアー・アクション中に例外が発生すると、現在のスレッド内にその例外が伝えられ、バリアーが故障状態に置かれます。

        戻り値:
        現在のスレッドの到着インデックス。インデックスgetParties() - 1は最初に到着するスレッドを、ゼロは最後に到着するスレッドを示す
        例外:
        InterruptedException - 待機中に現在のスレッドで割込みが発生した場合
        BrokenBarrierException - 現在のスレッドの待機中に別のスレッドで割込みが発生したかタイム・アウトした場合、バリアーがリセットされた場合、awaitが呼び出されたときにバリアーが破壊された場合、または例外のためにバリアー・アクション(存在する場合)が失敗した場合
      • await

        public int await​(long timeout,
                         TimeUnit unit)
                  throws InterruptedException,
                         BrokenBarrierException,
                         TimeoutException
        すべてのパーティがこのバリアーでawaitを呼び出すか、指定された待機時間が経過するまで待機します。

        現在のスレッドが、到着する最後のスレッドではない場合、スレッドのスケジューリングに関して無効になり、次のいずれかが起きるまで待機します。

        • 最後のスレッドが到着する
        • 指定されたタイム・アウトが経過する
        • ほかのスレッドが現在のスレッドに割り込みを行う。または
        • 別のスレッドが待機中の他のスレッドの1つに割り込みを行う
        • バリアーの待機中にほかのスレッドがタイム・アウトする
        • ほかのスレッドがこのバリアーに対してreset()を呼び出す。

        現在のスレッドで、

        • このメソッドへのエントリ上で設定された割込みステータスが保持されるか、
        • 待機中に割り込みが発生した場合
        InterruptedExceptionがスローされ、現在のスレッドの割込みステータスがクリアされます。

        指定された待機時間が経過すると、TimeoutExceptionがスローされます。 時間がゼロまたはそれより小さい場合、メソッドは待機しません。

        いずれかのスレッドが待機中にバリアーでreset()が実行されるか、awaitの呼出し時、またはいずれかのスレッドが待機中にバリアーが破壊された場合、BrokenBarrierExceptionがスローされます。

        待機中のいずれかのスレッドで割り込みが発生した場合、待機中の他のスレッドがすべてBrokenBarrierExceptionをスローし、バリアーが故障状態に置かれます。

        現在のスレッドが到着する最後のスレッドであり、コンストラクタ内でnullではないバリアー・アクションが指定される場合、現在のスレッドはアクションを実行してから、ほかのスレッドの続行を許可します。 バリアー・アクション中に例外が発生すると、現在のスレッド内にその例外が伝えられ、バリアーが故障状態に置かれます。

        パラメータ:
        timeout - バリアーを待機する時間
        unit - タイムアウト・パラメータの時間単位
        戻り値:
        現在のスレッドの到着インデックス。インデックスgetParties() - 1は最初に到着するスレッドを、ゼロは最後に到着するスレッドを示す
        例外:
        InterruptedException - 待機中に現在のスレッドで割込みが発生した場合
        TimeoutException - 指定されたタイム・アウトが経過した場合。 この場合はバリアーが破壊されます。
        BrokenBarrierException - 現在のスレッドの待機中に別のスレッドで割込みが発生したかタイム・アウトした場合、バリアーがリセットされた場合、awaitが呼び出されたときにバリアーが破壊された場合、または例外のためにバリアー・アクション(存在する場合)が失敗した場合
      • isBroken

        public boolean isBroken()
        このバリアーが故障状態にあるかどうかを問い合わせます。
        戻り値:
        バリアーの構築または最後のリセット以降に割り込みまたはタイム・アウトのために1つ以上のパーティがこのバリアーを破壊したか、または例外のためにバリアー・アクションが失敗した場合はtrue。それ以外の場合はfalse
      • reset

        public void reset()
        バリアーを初期状態にリセットします。 いずれかのパーティが現在バリアーで待機している場合、それらのパーティはBrokenBarrierExceptionで復帰します。 ほかの理由で切断が発生したあとにリセットする場合は、実行が複雑になる場合があることに注意してください。つまり、ほかの何らかの方法でスレッドを再同期し、リセットを実行するスレッドを選択する必要があります。 こうした状況では、以降で使用するためにバリアーを新規作成するほうが望ましい場合があります。
      • getNumberWaiting

        public int getNumberWaiting()
        バリアーで現在待機しているパーティの数を返します。 このメソッドは、主にデバッグとアサーションで役立ちます。
        戻り値:
        await()で現在ブロックされているパーティの数