引言
在写一个知识点之前,总是想说点废话。进程、线程之类的是操作系统级别上的概念,在此概念基础上使我们能够充分压榨CPU的处理能力,实现了并发和并行。但是呢,一涉及多线程的问题,总是有点不可控的感觉,对于线程的调度,很大程度上受操作系统调度算法的控制,而操作系统也开发了一些核心的api,可以让我们在用户的应用层面控制线程。
像CyclicBarrier就让我们在一定程度上,控制了多个线程的逻辑流,正常情况下,线程谁先执行,谁后执行是没法控制的。通过CyclicBarrier可以设置一个栅栏一样的东西,让多个线程都到达栅栏处才能继续往下执行。比如两个线程A、B,A执行的速度很快,很快到达了某一个点,但是此时B还慢悠悠的执行,此时线程A只能再栅栏处等待,直到线程B也到达栅栏处,才能继续往下执行。
下面直接从源码层面分析其实现原理。
实现原理
(1)实例化一个CyclicBarrier
提供了两个构造函数,parties表示有多少个个体(相当于调多少次await方法,每调一次await方法相当于一个线程到达了栅栏处),barrierAction其实相当于回调函数,当最后一个线程达到了栅栏处就会触发这个回调函数。
public CyclicBarrier(int parties) {
this(parties, null);
}
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
(2)核心方法await
// 这个方法不会超时,可以被中断
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;
// exclusive mode
lock.lock();
try {
final Generation g = generation;
// broken为true时,表示当前栅栏被打破,所有的线程都不会被阻塞了
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语句,表示最后一个线程到达栅栏处了
if (command != null)
command.run();
ranAction = true;
// 重新开始往栅栏冲刺
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
// 如果不设置超时,调用await释放锁,同时阻塞
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();
}
}
CyclicBarrier实现原理很简单,但是它却能控制多线程的行为,这是很值得称道的,而且这个类在
实际的开发中还是能够用到的。比如我们实现并行运算,一个线程算一部分数据,当算完之后,将多个结算汇总。