系列文章目录
线程安全(一)java对象头分析以及锁状态
线程安全(二)java中的CAS机制
线程安全(三)实现方法sychronized与ReentrantLock(阻塞同步)
线程安全(四)Java内存模型与volatile关键字
线程安全(五)线程状态和线程创建
线程安全(六)线程池
线程安全(七)ThreadLocal和java的四种引用
线程安全(八)Semaphore
线程安全(九)CyclicBarrier
线程安全(十)AQS(AbstractQueuedSynchronizer)
0.前言
CyclicBarrier:障碍器类,意为循环栅栏。也是JUC的工具类,依靠Condition和ReetrantLock实现了屏障功能,当所有子任务执行完成,屏障解除,下一任务才会继续,而且屏障会恢复。
1.源码解析
1.1.属性
// 可重入锁
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
// 条件
private final Condition trip = lock.newCondition();
/** The number of parties */
// 参与的线程数量
private final int parties;
/* The command to run when tripped */
// 当等待进入屏障数为0时,执行
private final Runnable barrierCommand;
/** The current generation */
// 当前代
private Generation generation = new Generation();
// 正在等待进入屏障的线程数量
private int count;
1.2.构造方法
// 屏障接触,执行barrierAction
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
// 无barrierAction
public CyclicBarrier(int parties) {
this(parties, null);
}
1.3.核心方法
当执行await方法时,和之前的带条件Condition的ReentrantLock 一样,会获取条件锁,当正在等待进入屏障数为0前,一直阻塞等待,等到为0时,执行barrierAction,并调用singleAll()方法
/**
* Main barrier code, covering the various policies. 主要代码,覆盖各种
*/
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时,执行指定任务,唤醒拦截的所有线程
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();
}
}
2.示例
2.1.测试
public class Test9_CyclicBarrier {
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
private static final CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
public static void main(String[] args) {
String[] nameArray = {"一", "二", "三", "四", "五", "六", "七"};//非整数倍栅栏数
for (int i = 0; i < nameArray.length; i++) {
Runnable t1 = new TaskThread(cyclicBarrier, nameArray[i]);
threadPool.execute(t1);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadPool.shutdown();;
}
static class TaskThread implements Runnable {
private String name;
private CyclicBarrier barrier;
public TaskThread(CyclicBarrier barrier, String name) {
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
Thread.currentThread().setName(name);
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 到达栅栏");
barrier.await();
System.out.println(Thread.currentThread().getName() + " 冲破栅栏");
} catch (Exception e) {
e.printStackTrace();
}
}
}
必选是整数倍栅栏数才可以关闭线程池,其他线程都处于await。
2.2.赛马
public class HorseRace implements Runnable {
private static final int FINISH_LINE = 75;
private static List<Horse> horses = new ArrayList<>();
private static ExecutorService exec = Executors.newCachedThreadPool();
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(7, new HorseRace());
for (int i = 0; i < 7; i++) {
Horse horse = new Horse(barrier);
horses.add(horse);
exec.execute(horse);
}
}
@Override
public void run() {
StringBuilder s = new StringBuilder();
//打印赛道边界
for (int i = 0; i < FINISH_LINE; i++) {
s.append("=");
}
System.out.println(s);
//打印赛马轨迹
for (Horse horse : horses) {
System.out.println(horse.tracks());
}
//判断是否结束
for (Horse horse : horses) {
if (horse.getStrides() >= FINISH_LINE) {
System.out.println(horse + "won!");
exec.shutdownNow();
return;
}
}
//休息指定时间再到下一轮
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
System.out.println("barrier-action sleep interrupted");
}
}
static class Horse implements Runnable {
private static int counter = 0;
private final int id = counter++;
private int strides = 0;
private int result;
private static Random rand = new Random(47);
private static CyclicBarrier barrier;
public Horse(CyclicBarrier b) {
barrier = b;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
//赛马每次随机跑几步
strides += rand.nextInt(7);
barrier.await();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String tracks() {
StringBuilder s = new StringBuilder();
for (int i = 0; i < getStrides(); i++) {
s.append("*");
}
s.append(id);
return s.toString();
}
public synchronized int getStrides() {
return strides;
}
@Override
public String toString() {
return "Horse " + id + " ";
}
}
}