java高并发、多线程(九)
CyclicBarrier
代码事例
先看一段代码:
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(2,() -> System.out.println(Thread.currentThread().getName() + "执行CyclicBarrier逻辑"));
for (int i = 0; i < 4; i++) {
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "start");
cb.await();
System.out.println(Thread.currentThread().getName() + "end");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"Thread-" + i).start();
}
}
}
运行结果:
功能:CyclicBarrier 会阻塞指定数量线程后运行已定义的Runnable接口,再唤醒阻塞线程继续执行。
源码结构
public class CyclicBarrier {
private static class Generation {
boolean broken = false;
}
//ReentrantLock锁
private final ReentrantLock lock = new ReentrantLock();
//等待触发条件
private final Condition trip = lock.newCondition();
//每部分的数量
private final int parties;
//触发后需要运行的逻辑
private final Runnable barrierCommand;
private Generation generation = new Generation();
//还需要等待多少数量
private int count;
//构造方法
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
this(parties, null);
}
}
事例执行流程
CyclicBarrier cb = new CyclicBarrier(2,() -> System.out.println(Thread.currentThread().getName() + "执行CyclicBarrier逻辑"));
首先jvm将加载CyclicBarrier类,然后再创建对象调用构造方法赋初始值。此时parties 、count 值为2,barrierCommand 为实现Runnable接口(System.out.println(Thread.currentThread().getName() + “执行CyclicBarrier逻辑”))的对象。
紧接着for循环陆续创建4个线程并启动。
- Thread-0(阻塞线程流程)
1、控制台打印Thread-0 start。
2、调用await()方法。
public int await() throws InterruptedException, BrokenBarrierException {
try {
//返回dowait()
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
继续查看dowait(false, 0L)方法
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
/*此处代码省略...*/
//count初始为2
int index = --count;
if (index == 0) { // tripped
/*此处代码省略...*/
}
for (;;) {
try {
//time : false
if (!timed)
//条件等待
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
/*此处代码省略...*/
}
/*此处代码省略...*/
}
} finally {
lock.unlock();
}
}
}
继续查看trip.await(); ConditionObject类中方法:
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//将此线程添加到条件等待队列中
Node node = addConditionWaiter();
//释放锁,调用dowait方法时,加了ReentrantLock 锁
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
//阻塞当前线程Thread-0,前面有一个释放锁的操作,同样也证明了LockSupport.park不会释放锁
LockSupport.park(this);
/*此处代码省略...*/
}
- Thread-2(达到条件线程流程)
开始流程与Thread-0一致,在dowait(false, 0L)方法中执行了不同分支逻辑
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
/*此处代码省略...*/
//经过Thread-0线程执行后,count值为1
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
//执行 System.out.println(Thread.currentThread().getName() + "执行CyclicBarrier逻辑")
command.run();
ranAction = true;
//更新状态并唤醒阻塞的线程
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
/*此处代码省略...*/
} finally {
lock.unlock();
}
}