CyclicBarrier当计数减少到0时,会唤醒所有阻塞在同一个Condition上的线程,与CountDownLatch不同的是所有的线程必须同时被唤醒,就好比钓鱼比赛,所有人必须同时开始抛竿一样。CountDownLatch只要求主线程的动作在其他依赖的线程执行完之后执行就OK
测试代码:
package com.jv.parallel.feature;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/*
* 处理同一个动作有多个线程同时执行的场景
*/
public class TestCyclicBarrier {
public static void main(String[] args) {
//1.得到一个CyclicBarrier实例
CyclicBarrier cb = new CyclicBarrier(4);
new Thread(new Fishing(cb),"1").start();
new Thread(new Fishing(cb),"2").start();
new Thread(new Fishing(cb),"3").start();
new Thread(new Fishing(cb),"4").start();
}
static class Fishing implements Runnable{
CyclicBarrier cb;
public Fishing(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
try {
cb.await();
System.out.println("第(" + Thread.currentThread().getName() + ")个人开始钓鱼");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
原理:
这里没有使用到什么设计模式,CyclicBarrier.await方法调用CyclicBarrier.dowait方法,每次调用await方法都会使计数器-1,当减少到0时就会唤醒所有的线程
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
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) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
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();
}
}
最核心的部分就是
每次调用await方法都会使内部的计数器临时变量-1,当减少到0时,就会调用nextGeneration方法
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
在这里唤醒所有阻塞的线程
提醒:在声明CyclicBarrier的时候还可以传一个Runnable的实现类,当计数器减少到0时,会执行该实现类