参考文章:http://www.jianshu.com/p/0c2af47f98fd
CyclicBarrier是同步辅助类,它允许一组线程相互等待,直到到达某个公共屏障点。
重要属性:
// 锁对象 lock
private final ReentrantLock lock = new ReentrantLock();
// trip 意思是 直到出错之前的条件
private final Condition trip = lock.newCondition();
// 参与者
private final int parties;
// barrier将执行的任务或者命令
private final Runnable barrierCommand;
// generation对象。Generation是其内部类
private Generation generation = new Generation();
// 记录未到达屏障点的线程数量,count = 0表示全部达到
private int count;
注意:维护count 和parties是由于CyclicBarrier复用性决定的,reset方法即可复用。
构造参数:
//指定了参与者数量的CyclicBarrier
CyclicBarrier(int parties);
/**
* 指定了参与者数量,并且当参与者都到达屏障点时,优先执行任务barrierAction
*
* /
CyclicBarrier(int parties, Runnable barrierAction);
// CyclicBarrier里面的内部类,它表示当前的CyclicBarrier是否是被损坏的。
// 默认broken为false是完整的。
private static class Generation {boolean broken = false;}
重要方法:
1.nextGeneration()它里面有三个操作,
trip.signalAll();// 唤醒所有线程
// set up next generation
count = parties;
generation = new Generation(); // 重新生成Generation对象
2.breakBarrier() 破坏CyclicBarrier
generation.broken = true;
count = parties;
trip.signalAll();
方法1、2是在reset回环屏障的时候调用的方法!
3.await(),它的内部是调用dowait(false, 0L);这里表示 不超时限制。
dowait(boolean timed, long nanos)这里的参数是:对于是否超时,及超时的限制。
dowait的内部实现是:
final ReentrantLock lock = this.lock;//获取到了显示锁。
lock.lock();
try {
final Generation g = generation; 获取CyclicBarrier的属性
//如果 CyclicBarrier 已损坏,就抛出异常BrokenBarrierException
if (g.broken)
throw new BrokenBarrierException();
//如果线程中断,破坏此CyclicBarrier并且抛出InterruptedException
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
// 指定线程数量--
int index = --count;
// tripped 当index ==0 表示,所有指定的数目都已到达指定的公共屏障点
if (index == 0) {
boolean ranAction = false;
try {
final Runnable command = barrierCommand;//把 barrierCommand属性赋给command
if (command != null) // 如果创建对象指定barrierAction,将执行run方法
command.run();
ranAction = true;
nextGeneration();//执行完之后调用nextGeneration,更新CyclicBarrier状态,并且唤醒所有线程
return 0;
} finally {
if (!ranAction) //如果 未成功完成上述try中的操作,ranAction为false则会破坏此CyclicBarrier
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock(); // finally释放锁,这点要注意
}
案例一
CyclicBarrier运行下述有顺序的执行分步任务,这是一个CountDownlatch做不到的!
public class CyclicBarrierTest2 {
private static CyclicBarrier cBarrier = null;
public static void main(String[] args) throws InterruptedException {
cBarrier = new CyclicBarrier(3);
for(int i=0;i<3;i++){
Thread party = new PartiesThread();
party.start();
}
Thread.sleep(3000);
System.out.println("正式开会...");
}
static class PartiesThread extends Thread{
@SneakyThrows
public void run(){
System.out.println(Thread.currentThread().getName()+"到了会议室");
cBarrier.await();
System.out.println(Thread.currentThread().getName() + "找到座位");
cBarrier.await();
System.out.println(Thread.currentThread().getName() + "准备开会");
}
}
}
案例二
重置回环屏障
public class CyclicBarrierTest3 {
private static CyclicBarrier cBarrier = null;
public static void main(String[] args) {
cBarrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("-----------");
}
});
for(int i=0;i<3;i++){
Thread party = new PartiesThread();
party.start();
if (i == 2) {
party.interrupt();
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cBarrier.reset();
for(int i=0;i<3;i++){
Thread party = new PartiesThread();
party.start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正式开会...");
}
static class PartiesThread extends Thread{
@SneakyThrows
public void run(){
System.out.println(Thread.currentThread().getName()+"到了会议室");
cBarrier.await();
System.out.println(Thread.currentThread().getName() + "找到座位");
cBarrier.await();
System.out.println(Thread.currentThread().getName() + "准备开会");
}
}
}