CyclicBarrier 介绍
CyclicBarrier 是用于阻塞固定数量的线程,数量达到时就继续这些线程的执行,并可以指定继续执行这些线程之前执行 Runnable, 这个 Runnable 是在到达临界数量的那个线程执行的。
例子如下:
private static CyclicBarrier caBarrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("阻塞结束,继续执行");
}
});
public static void main(String[] args) {
new Thread(){
public void run() {
System.out.println("线程一开始");
System.out.println("线程一等待执行");
try {
caBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程一继续执行");
System.out.println("线程一结束");
};
}.start();
new Thread(){
public void run() {
System.out.println("线程二开始");
System.out.println("线程二等待执行");
try {
caBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程二继续执行");
System.out.println("线程二结束");
};
}.start();
new Thread(){
public void run() {
System.out.println("线程三开始");
System.out.println("线程三等待执行");
try {
caBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程三继续执行");
System.out.println("线程三结束");
};
}.start();
打印结果:
线程一开始
线程一等待执行
线程二开始
线程二等待执行
线程三开始
线程三等待执行
阻塞结束,继续执行
线程三继续执行
线程三结束
线程二继续执行
线程二结束
线程一继续执行
线程一结束
CyclicBarrier 内部是通过记录一个阻塞线程的数量,每次调用 await() 都会减 1, 判断当前阻塞数量是否为 0, 为 0 则放开阻塞,await() 方法内部使用了 Lock 加锁来保证线程安全。
且 CyclicBarrier 是可重用的,这一轮的线程数量限制完之后,会再开始新的一轮的限制,例如把上面 caBarrier 创建时构造函数第一个参数改成 1, 执行结果如下:
线程一开始
线程一等待执行
阻塞结束,继续执行
线程一继续执行
线程一结束
线程二开始
线程二等待执行
阻塞结束,继续执行
线程二继续执行
线程二结束
线程三开始
线程三等待执行
阻塞结束,继续执行
线程三继续执行
线程三结束
CyclicBarrier 源码分析
创建 CyclicBarrier 对象时会指定线程的数量,以及等待数量完成后执行的 Runnable 对象,构造方法如下:
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
CyclicBarrier 在调用 await() 方法时会执行 doWait(false, 0L)
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// 通过 ReentrantLock 加锁保证多个线程同时调用问题
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
// ...
int index = --count;
if (index == 0) { // 当执行到最后一个线程的 wait 方法时会走到这里
boolean ranAction = false;
try {
// barrierCommand 是创建对象时指定的,所以这里可以看出是在最后一个 wait 的线程执行的
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 唤醒所有等待的线程,通过 LockSupport.unpark()
nextGeneration();
return 0;
} finally {
// ...
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
// 阻塞当前线程,通过调用 LockSupport.park()
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// ...
}
// ...
}
} finally {
lock.unlock();
}
}