簡介
- CyclicBarrier 是什麼?
- CyclicBarrier 使用
- CyclicBarrier 原始碼解析
- CyclicBarrier 簡單實現
- barrierAction 是由哪個執行緒執行的?
CyclicBarrier 是什麼?
CyclicBarrier 開始於JDK 1.5, 一個同步工具類,允許一組執行緒都等待彼此到達公共屏障點。CyclicBarrier 在程式中非常有用,涉及到固定引數的執行緒數量等待彼此,這個 barrier 被稱為 cyclic 是由於它可以所有的等待執行緒釋放之後,重複使用。
CyclicBarrier 支援一個可選的 Runnable 在每一個屏障點執行一次,在所有參與的執行緒到達之後,但是在執行之前所有的執行緒都釋放了, barrierAction非常有用的對於在任何參與者繼續之前更新共享狀態。
CyclicBarrier 使用
public class Test2 {
static class A extends Thread {
private CyclicBarrier cyclicBarrier;
public A(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
static class B extends Thread {
private CyclicBarrier cyclicBarrier;
public B(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
static class C extends Thread {
private CyclicBarrier cyclicBarrier;
public C(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> System.out.println("完成"));
new A(cyclicBarrier, "A").start();
new B(cyclicBarrier, "B").start();
new C(cyclicBarrier, "C").start();
}
}
/**
output:
A 準備完畢
B 準備完畢
C 準備完畢
完成
*/
CyclicBarrier 原始碼解析
在看原始碼前,我們可以對原始碼的實現進行一些猜想,根據 CyclicBarrier 前面的定義,可以猜想裡面有一個變數來表示參與者的數量,在使用呼叫 await 方法是時候,參與者的數量減一,直到參與者數量為 0,存在 barrierAction,就執行barrierAction,由於可以重複使用,所以在barrierAction 執行對參與者的數量進行恢復。
下面看一下原始碼實現是否於猜想的類似。
構造方法
parties 參與者的數量
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;
}
await 方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
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;
// 如果參與者數量為0,判斷barrierAction是否為null,不為null, 將執行run方法,呼叫nextGeneration恢復狀態
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();
}
}
nextGeneration 方法
private void nextGeneration() {
// signal completion of last generation
trip.signalAll(); // 喚醒參與者
// set up next generation
count = parties; // 恢復參與者的數量
generation = new Generation(); // 下一代
}
CyclicBarrier 簡單實現
藉助 AtomicInteger 來簡單實現
public class SimpleBarrier {
private AtomicInteger count;
int size;
private Runnable command;
public SimpleBarrier(int n) {
this.count = new AtomicInteger(n);
this.size = n;
}
public SimpleBarrier(int n, Runnable barrierAction) {
this(n);
this.command = barrierAction;
}
public void await() {
int position = count.getAndDecrement();
if (position == 1) {
command.run();
count.set(size);
} else {
while (count.get() != 0) {
}
}
}
}
public class Test2 {
static class A extends Thread {
private SimpleBarrier cyclicBarrier;
public A(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
}
}
static class B extends Thread {
private SimpleBarrier cyclicBarrier;
public B(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
}
}
static class C extends Thread {
private SimpleBarrier cyclicBarrier;
public C(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 準備完畢");
cyclicBarrier.await();
}
}
public static void main(String[] args) {
SimpleBarrier cyclicBarrier = new SimpleBarrier(3, () -> System.out.println("完成"));
new A(cyclicBarrier, "A").start();
new B(cyclicBarrier, "B").start();
new C(cyclicBarrier, "C").start();
}
}
/**
output:
A 準備完畢
B 準備完畢
C 準備完畢
完成
*/
barrierAction 是由哪個執行緒執行的?
最後一個執行緒來執行。