zoukankan      html  css  js  c++  java
  • CyclicBarrier(同步栅栏)源码分析

    /**
     * A synchronization aid that allows a set of threads to all wait for
     * each other to reach a common barrier point.  CyclicBarriers are
     * useful in programs involving a fixed sized party of threads that
     * must occasionally wait for each other. The barrier is called
     * <em>cyclic</em> because it can be re-used after the waiting threads
     * are released.
     */
    

    可以看到说明作用是使得一组线程互相等待至一个公共点再继续执行

        public CyclicBarrier(int parties, Runnable barrierAction) {
            if (parties <= 0) throw new IllegalArgumentException();
            this.parties = parties;
            this.count = parties;
            this.barrierCommand = barrierAction;
        }
    
     
        public CyclicBarrier(int parties) {
            this(parties, null);
        }
    
    

    构造方法有两个,高级一点的带barrierAction可以试打翻栅栏的时候先执行一个什么动作

     /**
         * Each use of the barrier is represented as a generation instance.
         * The generation changes whenever the barrier is tripped, or
         * is reset. There can be many generations associated with threads
         * using the barrier - due to the non-deterministic way the lock
         * may be allocated to waiting threads - but only one of these
         * can be active at a time (the one to which <tt>count</tt> applies)
         * and all the rest are either broken or tripped.
         * There need not be an active generation if there has been a break
         * but no subsequent reset.
         */
        private static class Generation {
            boolean broken = false;
        }
    
        /** The lock for guarding barrier entry */
        private final ReentrantLock lock = new ReentrantLock();
        /** Condition to wait on until tripped */
        private final Condition trip = lock.newCondition();
        /** The number of parties */
        private final int parties;
        /* The command to run when tripped */
        private final Runnable barrierCommand;
        /** The current generation */
        private Generation generation = new Generation();
    
        /**
         * Number of parties still waiting. Counts down from parties to 0
         * on each generation.  It is reset to parties on each new
         * generation or when broken.
         */
        private int count;
    

    这些是类的成员,可以看到条件变量trip用来触发所有线程的入场,parties一共有多少线程,count初始值为parties,慢慢会减少到0
    Generation描述着CyclicBarrier的更显换代。在CyclicBarrier中,同一批线程属于同一代。当有parties个线程到达barrier,generation就会被更新换代。其中broken标识该当前CyclicBarrier是否已经处于中断状态。

      /**
         * Returns the number of parties currently waiting at the barrier.
         * This method is primarily useful for debugging and assertions.
         *
         * @return the number of parties currently blocked in {@link #await}
         */
        public int getNumberWaiting() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return parties - count;
            } finally {
                lock.unlock();
            }
        }
    

    返回多少线程已经调用了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方法使得线程等待,有两个版本,一个带超时的

    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();
                }
    
               int index = --count;
               if (index == 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 {
                            // We're about to finish waiting even if we had not
                            // been interrupted, so this interrupt is deemed to
                            // "belong" to subsequent execution.
                            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();
            }
        }
    

    这是await的实现代码。

  • 相关阅读:
    pytest+allure生成测试报告
    pytest之fixture使用详解
    pytest框架介绍
    使用records库操作SQL并且查询MySQL数据库
    python模块之codecs
    项目总结
    第二阶段团队绩效评分
    软件发布2.0
    “随手记”开发记录day20
    “随手记”开发记录day19
  • 原文地址:https://www.cnblogs.com/encode/p/5912172.html
Copyright © 2011-2022 走看看