java多线程基本概述(二十三)——CyclicBarrier

java.util.concurrent
public class CyclicBarrier
extends Object
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 cyclic because it can be re-used after the waiting threads are released.
A CyclicBarrier supports an optional Runnable command that is run once per barrier point, after the last thread in the party arrives, but before any threads are released. This barrier action is useful for updating shared-state before any of the parties continue.
Sample usage: Here is an example of using a barrier in a parallel decomposition design:
   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 =
        new Runnable() { public void run() { mergeRows(...); }};
      barrier = new CyclicBarrier(N, barrierAction);
 
      List<Thread> threads = new ArrayList<Thread>(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();
    }
  }
Here, each worker thread processes a row of the matrix then waits at the barrier until all rows have been processed. When all rows are processed the supplied Runnable barrier action is executed and merges the rows. If the merger determines that a solution has been found then done() will return true and each worker will terminate.
If the barrier action does not rely on the parties being suspended when it is executed, then any of the threads in the party could execute that action when it is released. To facilitate this, each invocation of await returns the arrival index of that thread at the barrier. You can then choose which thread should execute the barrier action, for example:
   if (barrier.await() == 0) {
    // log the completion of this iteration
  }
The CyclicBarrier uses an all-or-none breakage model for failed synchronization attempts: If a thread leaves a barrier point prematurely because of interruption, failure, or timeout, all other threads waiting at that barrier point will also leave abnormally via BrokenBarrierException (or InterruptedException if they too were interrupted at about the same time).

翻译:

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
在这个例子中,每个 worker 线程处理矩阵的一行,在处理完所有的行之前,该线程将一直在屏障处等待。处理完所有的行之后,将执行所提供的 Runnable 屏障操作,并合并这些行。如果合并者确定已经找到了一个解决方案,那么 done() 将返回 true,所有的 worker 线程都将终止。
如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:
对于失败的同步尝试,CyclicBarrier 使用了一种要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。

它适用于这样一种情况:你希望创建一组任务,它们并行地执行工作,然后在进行下一个步骤之前,进行等待,直到所有任务完成,有点像join。它使得所有的并行任务都将在栅栏处列队,因此可以一致地向前移动。这非常像CountDownLatch.只是后者只触发一次时间,而前者可以多次重用。每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
例子:

package tij;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by huaox on 2017/4/21.
 *
 */
public class TestCylic {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("finish!");
            }
        });
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 5; i++) {
                        System.out.println(i+" "+Thread.currentThread().getName());
                    }
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        },"a").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 5; i < 10; i++) {
                        System.out.println(i+" "+Thread.currentThread().getName());
                    }
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        },"b").start();
    }
}

输出结果:

0 a
1 a
2 a
3 a
4 a
5 b
6 b
7 b
8 b
9 b
finish!

Process finished with exit code 0
package tij;

import java.util.*;
import java.util.concurrent.*;

class Horse implements Runnable{
    private static int count=0;
    private final int id = count++;
    private int strides = 0;
    private  static Random random = new Random(47);
    private  CyclicBarrier cyclicBarrier;

    Horse(CyclicBarrier cyclicBarrier){
        this.cyclicBarrier = cyclicBarrier;
    }
    synchronized int getStrides(){return this.strides;}

    @Override
    public String toString() {
        return "Horse " + id+ " ";
    }

    String tracks(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < getStrides(); i++) {
            sb.append("*");
        }
        sb.append(id);
        return sb.toString();
    }

    @Override
    public void run() {
            try {
                while (!Thread.interrupted()){
                    synchronized (this){
                        strides+=random.nextInt(3);
                    }
                    cyclicBarrier.await();//每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
                }
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }

    }
}

public class Test3 {
    private final int FINISH_LINE = 20;
    private List<Horse> horses = new ArrayList<>();
    private ExecutorService executorService = Executors.newCachedThreadPool();
    private  CyclicBarrier cyclicBarrier ;
    Test3(int n,final int pause){
        cyclicBarrier = new CyclicBarrier(n, new Runnable() {//第二个参数为一个task,当每个任务到达barrier时就被调用
            @Override
            public void run() {
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < FINISH_LINE; i++) {
                    sb.append("=");
                }
                System.out.println(sb);
                for (Horse hors : horses)
                    System.out.println(hors.tracks());
                for (Horse hors : horses) {
                    if (hors.getStrides() >= FINISH_LINE) {
                        System.out.println(hors+" win!");
                        executorService.shutdownNow();
                        return;
                    }
                }

                try {
                    TimeUnit.MILLISECONDS.sleep(pause);
                } catch (InterruptedException e) {
                    System.out.println("barrier sleep interrupted!");
                }
            }
        });
        for (int i = 1; i <= 7; i++) {
            Horse horse = new Horse(cyclicBarrier);
            horses.add(horse);
            executorService.execute(horse);
        }
    }

    public static void main(String[] args) {
      new Test3(7, 1000);
    }
}

输出结果:

====================
**0
**1
*2
**3
*4
**5
*6
====================
****0
**1
**2
**3
*4
**5
**6
====================
******0
***1
***2
***3
**4
****5
***6
====================
*******0
****1
***2
*****3
**4
******5
***6
====================
*********0
*****1
***2
******3
***4
******5
****6
====================
*********0
*****1
****2
******3
***4
********5
*****6
====================
**********0
******1
*****2
********3
****4
********5
*****6
====================
***********0
******1
*******2
*********3
******4
*********5
******6
====================
***********0
******1
*********2
*********3
******4
*********5
*******6
====================
************0
*******1
*********2
***********3
******4
***********5
********6
====================
**************0
*******1
**********2
*************3
******4
***********5
********6
====================
**************0
*********1
************2
***************3
*******4
************5
**********6
====================
***************0
***********1
**************2
***************3
********4
************5
**********6
====================
****************0
*************1
**************2
***************3
********4
**************5
***********6
====================
****************0
***************1
**************2
*****************3
********4
***************5
***********6
====================
******************0
*****************1
****************2
*****************3
*********4
****************5
***********6
====================
*******************0
*******************1
******************2
******************3
***********4
****************5
************6
====================
********************0
********************1
*******************2
********************3
***********4
****************5
************6
Horse 0  win!

Process finished with exit code 0

 

posted @ 2017-04-20 23:12  soar_hu  阅读(137)  评论(0编辑  收藏  举报