CyclicBarrier描述
作用:
假如现在有三个任务,要等着3个任务都执行到否一阶段再一起向下执行,使用CyclicBarrier可以很好的解决
CyclicBarrier可以多次使用
可能你看了countDwonLatch的实现原理,感觉都是都是传递一个基数,应该都是递减,实现原理应该类似
其实,都是递减基数是对的,但是实现原理,差异很大
countDwonLatch 是 直接使用 AQS 实现的
CyclicBarrier 则是通过 lock锁+condition 实现的
大致实现逻辑:
以上面的例子来说:
1.新建一个 cyclicBarrier 传入参数 parties 值为 3
2.构造函数中,会把这个parties 复制出一份 count, 用作递减的具体数值,这也是cyclicBarrier可以多次使用的原因.
3.当其中一个线程执行到了需要等待的地方,那么他就会去检查count是否为0,这里面使用了lock,所以存在了condition
4.假如检查count 结果不为0 那么就会把当前线程放入 condition 等待队列 中
5.总有一个线程
实例dome
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3,() -> {
System.out.println("先执行当前任务");
}) ;
for(int a=0; a<3; a++) {
new Thread(() ->{
try {
Thread.sleep((long) Math.random() * 2000);
int randomInt = new Random().nextInt(500);
System.out.println("hello"+randomInt);
cyclicBarrier.await();
System.out.println("world"+randomInt);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} ).start();
}
}
hello275
hello31
hello187
先执行当前任务
world187
world275
world31
源码分析
构造函数
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
await
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe);
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) {
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
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 {
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();
}
}