Java 并发编程(十四) — CyclicBarrier源码分析

public class CyclicBarrier
复制代码

2. 字段属性

//独占
private final ReentrantLock lock = new ReentrantLock();
//等待的条件
private final Condition trip = lock.newCondition();
//线程等待的数量,重置count
private final int parties;
//被唤醒时,优先执行的任务
private final Runnable barrierCommand;
//描述更新换代,重置?
//Generation中的broken表示这一次是否完成,默认false。count为0时设置为true
private Generation generation = new Generation();
//记录当前需要等待到来的线程数,等于0表示到下一代,通过parties来重置
private int count;
复制代码

从字段属性可以看出

  • CyclicBarrier使用ReentrantLock来达到同步功能
  • 所有的线程等待Condition唤醒,即count为0的时候唤醒所有线程
  • CyclicBarrier的重置功能使用Generation和parties来完成
  • CyclicBarrier可以使用barrierCommand处理一部份逻辑

3. 构造方法

//传入线程数量
public CyclicBarrier(int parties) {
    	//调用下面的构造方法
        this(parties, null);
    }

//传入线程数量和要处理的业务
public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
复制代码

从构造方法可以看出

  • count使用parties初始化
  • barrierCommand可以为null

4. 方法

nextGeneration 方法

//设置为新生代,唤醒线程并重置状态
private void nextGeneration() {
        //唤醒所有等待condition的线程
        trip.signalAll();
        //重置count
        count = parties;
    	//重置generation,新生代
        generation = new Generation();
    }
复制代码

breakBarrier 方法

//设置当前代为完成状态
private void breakBarrier() {
    	//设置当前代为完成状态
        generation.broken = true;
    	//重置count
        count = parties;
    	//唤醒所有等待condition的线程
        trip.signalAll();
    }
复制代码

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();
            }
            //count减1
            int index = --count;
            if (index == 0) {  // tripped
                //如果count为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)
                    return index;

                if (timed && nanos <= 0L) {
                    //超时
                   //设置当前代为完成状态
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            //释放锁资源
            lock.unlock();
        }
    }
复制代码

getParties 方法

//获取设置等待的线程数
public int getParties() {
        return parties;
    }
复制代码

await 方法

//进入条件等待
public int await() throws InterruptedException, BrokenBarrierException {
        try {
            //调用dowait方法
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
//进入有超时时间的条件等待
public int await(long timeout, TimeUnit unit)
        throws InterruptedException,
               BrokenBarrierException,
               TimeoutException {
                   //调用dowait方法
        return dowait(true, unit.toNanos(timeout));
    }
复制代码

isBroken 方法

//获取当前代状态
public boolean isBroken() {
    	//上锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //返回当前代状态
            return generation.broken;
        } finally {
            //释放锁资源
            lock.unlock();
        }
    }
复制代码

reset 方法

//重置当前代状态
public void reset() {
    	//上锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //设置当前代为完成状态
            breakBarrier();   // break the current generation
            //设置为新生代代,唤醒线程并重置状态
            nextGeneration(); // start a new generation
        } finally {
            //释放锁
            lock.unlock();
        }
    }
复制代码

getNumberWaiting 方法

//获取等待中的线程数
public int getNumberWaiting() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //parties 需要的线程总数
            //count 还需要等待到来的线程数
            return parties - count;
        } finally {
            lock.unlock();
        }
    }
复制代码

原文 

https://juejin.im/post/5e6ee750f265da575477ac22

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Java 并发编程(十四) — CyclicBarrier源码分析

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址