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();
}
}
}