JUC-- CyclicBarrier学习(二)源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ONROAD0612/article/details/82454014

1 概述

通过前面对CyclicBarrier(请参考JUC-- CyclicBarrier学习(一)简介和使用)的介绍,我们对CyclicBarrier的使用有了一个深度的认识,现在就要针对CyclicBarrier的源码进行分析,CyclicBarrier的结构如下:

从上图我们可以猜想CyclicBarrier的实现主要就是依靠ReentrantLock和Condition。

2 属性

首先我们这里来看一下CyclicBarrier属性的意义。

    //进入Barrier的锁 
    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;

从上面的代码我们发现了一个很重要的类Genertion,这个类的源码如下:

private static class Generation {
        boolean broken = false;
    }

这个类的主要作用就是表示一次CyclicBarrier的使用,当broken属性位true的时候就表示本次使用结束。

3 构造函数

CyclicBarrier有两个构造函数,但是最终其实所有的初始化都是通过一个构造函数来完成的,所以我们这里直接来看看这个构造函数做了哪些事。

public CyclicBarrier(int parties, Runnable barrierAction) {

        //当使用循环屏障的线程数小于0的时候直接抛出异常
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

上面的构造函数做了三件事:

(1)设置需要到达屏障点的线程数量。

(2)设置剩余需要到达屏障点的线程数量,这里和parties相等。

(3)设置所有需要到达屏障点的线程到达屏障点后需要执行的动作。

4 await函数

我们可以发现在使用CyclicBarrier的时候,主要使用的就是await函数,所以这里我们仅仅对await函数进行分析。其余的可以自行查看源码了解。

这里我们先来看一下await函数的调用顺序。

我们直到调用了await方法后,在所有参与了barrier的方法调用await之前将一直等待。接下来我们来看一看await的源码。

public int await() throws InterruptedException, BrokenBarrierException {
        try {
            
            //直接返回dowait的调用结果
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

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;
            
            //当前generation“已损坏”,抛出BrokenBarrierException异常
            //抛出该异常一般都是某个线程在等待某个处于“断开”状态的CyclicBarrie            
            if (g.broken)
                throw new BrokenBarrierException();
            
            //如果当前线程中断,终止CyclicBarrier           
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
           
            
            //进来一个线程 count - 1
            int index = --count;

            //count == 0 表示所有线程均已到位,触发Runnable任务 
            if (index == 0) {
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;

                    //触发任务
                    if (command != null)
                        command.run();
                    ranAction = true;

                    //唤醒所有等待线程,并更新generation
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            for (;;) {
                try {

                    //如果不是超时等待,则调用Condition的await进行等待
                    if (!timed)
                        trip.await();

                    //如果是超时等待,则调用Condition的awaitNanos进行等待
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {

                    //当前代发生线程中断的异常则终止CyclicBarrier
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                //generation已经更新,返回index
                if (g != generation)
                    return index;
                
                
                //“超时等待”,并且时间已到,终止CyclicBarrier,并抛出异常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {

            //释放锁
            lock.unlock();
        }
    }

从上面的源码我们可以看出CyclicBarrier的实现主要是依靠ReentrantLock和Condition。

接下来我们来看看两个比较重要的函数breakBarrier和nextGeneration做了些什么。

    /**
     * 设置当前屏障代无法使用,并且唤醒所有在屏障点等待的线程,
     * 注意这里没有生成新的屏障代,所以CyclicBarrier无法继续使用
     */
    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }

    
    /**
     * 生成新的屏障代,并且唤醒所有在屏障点等待的线程
     */
    private void nextGeneration() {
        //唤醒所有在屏障点等待的线程
        trip.signalAll();
        count = parties;
        
        //生成新的屏障代,以保证CyclicBarrier可以多次使用
        generation = new Generation();
    }

到此,已经对CyclicBarrier有了一个深入的学习,后面会继续学习并总结JUC下面的内容。

谢谢关注,如有不同看法欢迎指正。

猜你喜欢

转载自blog.csdn.net/ONROAD0612/article/details/82454014