栅栏(Barrier)
栅栏(Barrier):如果说CountDownLatch是一扇打开了就永远关不上的门,那么栅栏就是一扇能反反复复打开关闭的门。例如:大家应该都跟过团去旅游,早上,大家陆陆续续来到出发点集合乘车等待出发,导游清点人头后出发,到达景区后大家自由活动,然后回到集合点集合上车准备前往下一个景点。
API如下:
// 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动
// barrier 时执行预定义的操作。
public CyclicBarrier(int parties)
// 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时
// 执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
public CyclicBarrier(int parties, Runnable barrierAction)
// 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
public int await() throws InterruptedException, BrokenBarrierException
// 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
public int await(long timeout,TimeUnit unit) throws InterruptedException, BrokenBarrierException,TimeoutException
// 返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言
public int getNumberWaiting() 。
// 返回要求启动此 barrier 的参与者数目。
public int getParties()
// 查询此屏障是否处于损坏状态。
public boolean isBroken()
// 将屏障重置为其初始状态。
public void reset()
下面代码示例了一个 CPU数+1(main线程)的Barrier:当CPU数线程启动完毕后,main线程通知Barrier进入等待状态,这时Barrier开放,之前启动的CPU数线程和主main线程继续执行,拦截的线程通过后,Barrier自动恢复,main线程启动的下一轮CPU线程全部被Barrier阻塞,直到Barrier再次开放。
/*
* TestBarrier
*
* @author alchimie
*/
public class TestBarrier {
private final CyclicBarrier barrier;
private final int runNum;
private final Random random = new Random();
private final int nCpu;
public TestBarrier(int runNum) {
this.nCpu = Runtime.getRuntime().availableProcessors();
System.out.println("本机CPU为: " + nCpu + " 栅栏限制线程数为:" + (nCpu + 1));
barrier = new CyclicBarrier(nCpu + 1, new worker(
"Thread-worker"));
this.runNum = runNum;
}
private class worker implements Runnable {
private final String name;
public worker(String name) {
this.name = name;
}
public void run() {
System.out.println(name + " 栅栏开放");
}
}
private class randomIntWorker implements Runnable {
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 到达栅栏");
barrier.await();
int randomVal = random.nextInt(10);
System.out.println(Thread.currentThread().getName() + " 取得随机数:"
+ randomVal);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void execute() {
for (int i = 0; i < nCpu * runNum; i++) {
new Thread(new randomIntWorker()).start();
if ((i + 1) % nCpu == 0) {
try {
// 主线程等待栅栏
barrier.await();
} catch (InterruptedException e) {
return;
} catch (BrokenBarrierException e) {
return;
}
}
}
}
public static void main(String args[]) {
// 设置执行两轮
TestBarrier tb = new TestBarrier(2);
tb.execute();
}
}
执行结果:
本机CPU为: 4 栅栏限制线程数为:5
Thread-0 到达栅栏
Thread-1 到达栅栏
Thread-2 到达栅栏
Thread-3 到达栅栏
Thread-worker 栅栏开放
Thread-3 取得随机数:5
Thread-2 取得随机数:9
Thread-0 取得随机数:4
Thread-1 取得随机数:4
Thread-4 到达栅栏
Thread-5 到达栅栏
Thread-6 到达栅栏
Thread-7 到达栅栏
Thread-worker 栅栏开放
Thread-7 取得随机数:6
Thread-4 取得随机数:8
Thread-6 取得随机数:9
Thread-5 取得随机数:1