JUC之CyclicBarrier源码分析

关于CyclicBarrier

CyclicBarrier是JUC包中提供的多线程同步工具类,可以设置一个集合点,线程到达该集合点之后都需要阻塞,直到所有线程都到达该集合点,才能执行下一步操作,并且支持重复使用。

简单示例

public static void main(String[] args) {

    CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
        @Override
        public void run() {
            System.out.println("所有线程已到达集合点...");
        }
    });

    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "到达集合点");
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "Thread-" + i).start();
    }

}

源码分析

成员变量分析

// 同步锁,保证await()方法在同一时刻只有一个线程执行
private final ReentrantLock lock = new ReentrantLock();
// 调用await()方法可以释放lock.lock()获取的锁,并使当前线程阻塞
// 调用signal()或signalAll()方法唤醒调用await方法阻塞的线程
private final Condition trip = lock.newCondition();
// 需要到达集合点的线程总数
private final int parties;
// 所有线程到达集合点之后回调接口,可以为空
private final Runnable barrierCommand;
// 标记当前CyclicBarrier的状态
private Generation generation = new Generation();
// 计数器,剩余需要到达集合点的线程数(调用await()方法,该值就会-1)
private int count;

private static class Generation {
    // CyclicBarrier中断标识,线程中断、await超时,执行过程异常,都会修改该标识为true
    boolean broken = false; 
}

构造函数分析

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    // 需要到达集合点的线程数
    this.parties = parties;
    // 计数器,剩余到达集合点的线程数(使用该变量就是为了重复使用,当所有线程都到达集合点之后,会将该值重置为parties,后续线程再调用await()方法又可以实现阻塞,达到重复使用的效果)
    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
    }
}

public int await(long timeout, TimeUnit unit)
    throws InterruptedException,
           BrokenBarrierException,
           TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}
await()方法调用有两种方式,一种永不超时,一种可以设置超时时间,底层最终都调用了dowait()方法。
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();
        }

        // 剩余线程数-1
        int index = --count;
        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();
            }
        }

        // 自选,阻塞,等待所有线程全部到达屏障后被其他线程唤醒
        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)
                return index;

            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}

// 主要做三件事
// 1.设置屏障已经被中断,其他线程调用await()方法直接抛出异常
// 2.重置count内容,即重置屏障
// 3.唤醒所有阻塞线程
private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
}

// 重置屏障,供下一次使用
private void nextGeneration() {
    // signal completion of last generation
    trip.signalAll();
    // set up next generation
    count = parties;
    generation = new Generation();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值