多线程 - CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

示例用法:下面是一个在并行分解设计中使用 barrier 的例子:

 1 class Solver {
 2    final int N;
 3    final float[][] data;
 4    final CyclicBarrier barrier;
 5    
 6    class Worker implements Runnable {
 7      int myRow;
 8      Worker(int row) { myRow = row; }
 9      public void run() {
10        while (!done()) {
11          processRow(myRow);
12 
13          try {
14            barrier.await(); 
15          } catch (InterruptedException ex) { 
16 return; 
17          } catch (BrokenBarrierException ex) { 
18 return; 
19          }
20        }
21      }
22    }
23 
24    public Solver(float[][] matrix) {
25      data = matrix;
26      N = matrix.length;
27      barrier = new CyclicBarrier(N, 
28                                  new Runnable() {
29                                    public void run() { 
30                                      mergeRows(...); 
31                                    }
32                                  });
33      for (int i = 0; i < N; ++i) 
34        new Thread(new Worker(i)).start();
35 
36      waitUntilDone();
37    }
38  }

 

在这个例子中,每个 worker 线程处理矩阵的一行,在处理完所有的行之前,该线程将一直在屏障处等待。处理完所有的行之后,将执行所提供的 Runnable 屏障操作,并合并这些行。如果合并者确定已经找到了一个解决方案,那么 done() 将返回 true,所有的 worker 线程都将终止。

如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:

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

对于失败的同步尝试,CyclicBarrier 使用了一种快速失败的、要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么其他所有线程(甚至是那些尚未从以前的 await() 中恢复的线程)也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。

 

posted @ 2016-11-18 18:34  ck_2016  Views(262)  Comments(0Edit  收藏  举报