CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。 CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
JDK1.8官方示例
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(); } }
在这个例子中,每个 worker 线程处理矩阵的一行,在处理完所有的行之前,该线程将一直在屏障处等待。处理完所有的行之后,将执行所提供的 Runnable 屏障操作,并合并这些行。如果合并者确定已经找到了一个解决方案,那么 done() 将返回 true,所有的 worker 线程都将终止。 如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如: if (barrier.await() == 0) { // log the completion of this iteration } 对于失败的同步尝试,CyclicBarrier 使用了一种要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。 内存一致性效果:线程中调用 await() 之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 紧跟在从另一个线程中对应 await() 成功返回的操作。
详情请见:https://docs.oracle.com/javase/8/docs/api/
方式一:CyclicBarrier(int parties)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
import java.util.Random; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierTest { public static void main(String[] args) throws InterruptedException, BrokenBarrierException { CyclicBarrier barrier = new CyclicBarrier(2); Thread thread1 = new Thread(new XThread(barrier), "1号线程"); Thread thread2 = new Thread(new XThread(barrier), "2号线程"); thread1.start(); thread2.start(); System.out.println(Thread.currentThread().getName() + "执行"); } } class XThread implements Runnable { private CyclicBarrier barrier; public XThread(CyclicBarrier barrier) { this.barrier = barrier; } public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(5)); System.out.println(Thread.currentThread().getName() + " 等待"); barrier.await(); System.out.println(Thread.currentThread().getName() + " 继续"); } catch (Exception e) { e.printStackTrace(); } } }
方式二:CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
import java.util.Random; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args) throws InterruptedException, BrokenBarrierException { CyclicBarrier barrier = new CyclicBarrier(2, new Thread("barrierAction") { public void run() { System.out.println(Thread.currentThread().getName() + " 栅栏"); } }); Thread thread1 = new Thread(new SonThread(barrier), "1号线程"); Thread thread2 = new Thread(new SonThread(barrier), "2号线程"); thread1.start(); thread2.start(); System.out.println(Thread.currentThread().getName() + "执行"); } } class SonThread implements Runnable { private CyclicBarrier barrier; public SonThread(CyclicBarrier barrier) { this.barrier = barrier; } public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(5)); System.out.println(Thread.currentThread().getName() + " 等待"); barrier.await(); System.out.println(Thread.currentThread().getName() + " 继续"); } catch (Exception e) { e.printStackTrace(); } } }