CyclicBarrier原理分析

CyclicBarrier循环的栅栏。使用上,与CountDownLatch类似,也不太一样。这两个类都是用来解决线程同步问题的。同步问题说的通俗一点就是线程间通信。

CountDownLatch,是主线程等待所有子线程结束任务

CyclicBarrier,是多个子线程互相等待

下面看看CyclicBarrier的源码实现

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;// 需要汇集的线程的个数,是一个不变量。用来做重置
    this.count = parties;// 需要汇集的线程的个数,用来做计数
    this.barrierCommand = barrierAction;// 线程汇集到一点后的回调异步任务
}

// parties,需要汇集的线程的个数
public CyclicBarrier(int parties) {
    this(parties, null);
}

两种构造方式,一种是带有Runnable回调的,一种没有。带有回调是指当多个子线程汇集到一点后,可以执行一个异步任务,后面会分析到。

private static class Generation {
    boolean broken = false;// 栅栏是否被破坏的标识
}
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();// 每个新的栅栏会new这么一个对象
private int count;// 需要汇集的线程的个数,用来做计数

上面是一堆成员变量,各自的用途已经在注释中写明。下面看跟API相关的几个方法。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));
}

无论是限时等待还是不限时等待,都会去调用dowait方法。重点在这个dowait方法。

private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException {
    final ReentrantLock lock = this.lock;
    lock.lock();// 线程进来先上锁,所以这边用的一定是可重入锁
    try {
        final Generation g = generation;// 把generation暂时保存一下,后面比对用

        if (g.broken)// 如果栅栏已经被破坏,则抛出已经被破坏的异常
            throw new BrokenBarrierException();

        if (Thread.interrupted()) {// 如果检测到当前线程被打断,则把整个栅栏都通知破坏了。因为其他线程再等待也等不来。
            breakBarrier();
            throw new InterruptedException();
        }

        int index = --count;// 来一个线程,计数器-1
        if (index == 0) {  // 如果计数器减到0,说明所有线程都汇集到某一点了。
            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 {// 其他线程破坏了栅栏
                    Thread.currentThread().interrupt();// 自我中断
                }
            }

            if (g.broken)// 再看看栅栏是否被破坏
                throw new BrokenBarrierException();

            if (g != generation)// 如果generation刷新说明成功了。返回即可
                return index;

            if (timed && nanos <= 0L) {// 超时情况,破坏栅栏
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值