AQS 之 CyclicBarrier 源码分析

1:CyclicBarrier 基本知识

1:字面意思是可循环使用(Cyclic)的屏障(Barrier)。让一组线程全部到达屏障时,屏障才会开门,被屏障拦截的线程才会继续运行。先到达的线程处于阻塞状态。
2:使用场景:可以用于多线程计算数据,最后合并结果的场景。
3:CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。
4:一般和固定数目线程池配合使用,线程数目二者最好定义相同

2:构造方法

默认构造方法 :传入拦截的线程总数

    public CyclicBarrier(int parties) {
        // 调用重载方法,也就是另外的构造方法
        this(parties, null);
    }

进入重载方法:另一个构造方法

    public CyclicBarrier(int parties, Runnable barrierAction) {
        // 拦截的线程数目不能 <=0,否则会抛出异常
        if (parties <= 0) throw new IllegalArgumentException();
        // 传入一个任务,当线程到达屏障时,优先执行这个任务
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

3:阻塞方法 await

需要等待的线程需要调用 await() 方法

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            // 进入 dowait(false, 0L) 方法
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

进入 dowait(false, 0L) 方法

    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        // 可以看出内部有一个 ReentrantLock 锁  
        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 ,判断 减 1 后是否等于 0 
            int index = --count;
            if (index == 0) {  
                boolean ranAction = false;
                try {
                    // 如果构造器传进来的优先任务不为 null, 优先执行
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    // 进入 nextGeneration()  方法
                    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();
        }
    }

进入 nextGeneration() 方法

    private void nextGeneration() {
        // 进入 Condition.signalAll() 方法
        trip.signalAll();
        count = parties;
        generation = new Generation();
    }

进入 Condition.signalAll() 方法

        public final void signalAll() {
            // 判断拥有 ReentrantLock 锁的线程是不是当前线程,不是的话抛出异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            // Conditinon 中的第一个节点,如果不为空,进入 doSignalAll(first) 方法
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
        }

进入 doSignalAll(first) 方法

        private void doSignalAll(Node first) {
            // 将 Conition 的节点删除移动到 AQS 的等待队列中,只不过所有节点的顺序往后推一位,头节点是亚元节点
            lastWaiter = firstWaiter = null;
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

回到 nextGeneration() 方法

    private void nextGeneration() {
        //  Condition.signalAll() :将 Condition 节点删除移动到 AQS 等待队列
        trip.signalAll();
        count = parties;
        // 创建一个新的实例,屏障的每次新的使用都会创建一个实例
        generation = new Generation();
    }

回到 dowait(false, 0L) 方法

    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        // 可以看出内部有一个 ReentrantLock 锁  
        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 ,判断 减 1 后是否等于 0 
            int index = --count;
            if (index == 0) {  
                boolean ranAction = false;
                try {
                    // 如果构造器传进来的优先任务不为 null, 优先执行
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    // 进入 nextGeneration()  方法
                    nextGeneration();
                    return 0;
                } finally {
                // ranAction 等于 true,不满足条件
                    if (!ranAction)
                        breakBarrier();
                }
            }
            // 屏障数目 减 1  大于 0,如果进入 for 循环
            for (;;) {
                try {
                   // 如果没有传等待时间,那么进入 Condition.await() 方法;否则进入超时的Condition.awaitNanos()方法
                  // 生成一个新的节点,添加到 Conditon 双向链表的尾端,释放节点上持有的同步锁,并阻塞住
                    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 {
            // 最后 ReentrantLock 进行解锁
            lock.unlock();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值