接着说另外一个同步器CyclicBarrier,在jdk的文档中是这么描述的:“一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。 ”,同时在描述CountDownLatch中也说道“用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用CyclicBarrier",这就给出了两者之间的关系,CyclicBarrier 是CountDownLatch的一个扩展。
上篇文章举了赛跑的例子,选手跑完之后颁奖则不再有后续的活动,假如说以下这个例子,场景:有几个人通过不同的路线做宣传活动,第一站要先到北京,在北京集结(都要到达)之后再以不同的路线前往杭州,而在杭州也要集结,然后同时以不同的路现前往广州。 如果是这么一种情况CountDownLatch则无能为力了,下面的代码是使用CyclicBarrier 来实现的:
package com.test.concurrent.cyclicBarrier;
import java.util.concurrent.CyclicBarrier;
import com.test.util.AppRandom;
import com.test.util.SleepUtil;
public class CyclicBarrierDemo {
public static CyclicBarrier getFirstCyclicBarrier(int count) {
if (count <= 0)
return null;
final CyclicBarrier cyclicBarrier = new CyclicBarrier(count,
new Runnable() {
public void run() {
SleepUtil.sleep(100);
System.out.println("》》》》》》所有人员都已经到达北京》》》》》》》》开始下一步行动:目的地杭州");
}
});
return cyclicBarrier;
}
public static CyclicBarrier getSecondCyclicBarrier(int count) {
if (count <= 0)
return null;
final CyclicBarrier cyclicBarrier = new CyclicBarrier(count,
new Runnable() {
public void run() {
SleepUtil.sleep(100);
System.out.println("》》》》》》所有人员都已经到达杭州》》》》》》》》开始下一步行动:目的地广州");
}
});
return cyclicBarrier;
}
public static Thread getThread(String nameOfThread,
final CyclicBarrier cyclicBarrier1,final CyclicBarrier cyclicBarrier2) {
Thread thread = new Thread(nameOfThread) {
public void run() {
SleepUtil.sleep(AppRandom.getNumber(4));
System.out.println(this.getName() + " 到达北京; 序号: " + (++count));
try {
cyclicBarrier1.await();
SleepUtil.sleep(AppRandom.getNumber(4));
System.out.println(this.getName() + " 到达杭州; 序号: " + (++count));
cyclicBarrier2.await();
} catch (Exception e) {
e.printStackTrace();
}
// System.out.println(this.getName() + " 开始前往广州");
}
};
return thread;
}
static int count = 0;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier1 = getFirstCyclicBarrier(3);
CyclicBarrier cyclicBarrier2 = getSecondCyclicBarrier(3);
Thread threadOne = getThread("路人甲", cyclicBarrier1, cyclicBarrier2);
threadOne.start();
Thread threadTwo = getThread("路人乙", cyclicBarrier1, cyclicBarrier2);
threadTwo.start();
Thread threadThree = getThread("路人丙", cyclicBarrier1, cyclicBarrier2);
threadThree.start();
}
}
这个片段可以运行,运行结果是(线程完成的顺序未必一致,但是中间的集结状态肯定是一致的):
路人丙 到达北京; 序号: 1
路人乙 到达北京; 序号: 2
路人甲 到达北京; 序号: 3
》》》》》》所有人员都已经到达北京》》》》》》》》开始下一步行动:目的地杭州
路人乙 到达杭州; 序号: 4
路人丙 到达杭州; 序号: 5
路人甲 到达杭州; 序号: 6
》》》》》》所有人员都已经到达杭州》》》》》》》》开始下一步行动:目的地广州