• Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例


    概要

    本章介绍JUC包中的CyclicBarrier锁。内容包括:
    CyclicBarrier简介
    CyclicBarrier数据结构

    CyclicBarrier源码分析(基于JDK1.7.0_40)
    CyclicBarrier示例

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3533995.html

    CyclicBarrier简介

    CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

    注意比较CountDownLatchCyclicBarrier
    (01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
    (02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。


    CyclicBarrier函数列表

    CyclicBarrier(int parties)
    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
    CyclicBarrier(int parties, Runnable barrierAction)
    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
    
    int await()
    在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
    int await(long timeout, TimeUnit unit)
    在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
    int getNumberWaiting()
    返回当前在屏障处等待的参与者数目。
    int getParties()
    返回要求启动此 barrier 的参与者数目。
    boolean isBroken()
    查询此屏障是否处于损坏状态。
    void reset()
    将屏障重置为其初始状态。

    CyclicBarrier数据结构

    CyclicBarrier的UML类图如下:

    CyclicBarrier是包含了"ReentrantLock对象lock"和"Condition对象trip",它是通过独占锁实现的。下面通过源码去分析到底是如何实现的。

    CyclicBarrier源码分析(基于JDK1.7.0_40)

    CyclicBarrier完整源码(基于JDK1.7.0_40)

      1 /*
      2  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
      3  *
      4  *
      5  *
      6  *
      7  *
      8  *
      9  *
     10  *
     11  *
     12  *
     13  *
     14  *
     15  *
     16  *
     17  *
     18  *
     19  *
     20  *
     21  *
     22  *
     23  */
     24 
     25 /*
     26  *
     27  *
     28  *
     29  *
     30  *
     31  * Written by Doug Lea with assistance from members of JCP JSR-166
     32  * Expert Group and released to the public domain, as explained at
     33  * http://creativecommons.org/publicdomain/zero/1.0/
     34  */
     35 
     36 package java.util.concurrent;
     37 import java.util.concurrent.locks.*;
     38 
     39 /**
     40  * A synchronization aid that allows a set of threads to all wait for
     41  * each other to reach a common barrier point.  CyclicBarriers are
     42  * useful in programs involving a fixed sized party of threads that
     43  * must occasionally wait for each other. The barrier is called
     44  * <em>cyclic</em> because it can be re-used after the waiting threads
     45  * are released.
     46  *
     47  * <p>A <tt>CyclicBarrier</tt> supports an optional {@link Runnable} command
     48  * that is run once per barrier point, after the last thread in the party
     49  * arrives, but before any threads are released.
     50  * This <em>barrier action</em> is useful
     51  * for updating shared-state before any of the parties continue.
     52  *
     53  * <p><b>Sample usage:</b> Here is an example of
     54  *  using a barrier in a parallel decomposition design:
     55  * <pre>
     56  * class Solver {
     57  *   final int N;
     58  *   final float[][] data;
     59  *   final CyclicBarrier barrier;
     60  *
     61  *   class Worker implements Runnable {
     62  *     int myRow;
     63  *     Worker(int row) { myRow = row; }
     64  *     public void run() {
     65  *       while (!done()) {
     66  *         processRow(myRow);
     67  *
     68  *         try {
     69  *           barrier.await();
     70  *         } catch (InterruptedException ex) {
     71  *           return;
     72  *         } catch (BrokenBarrierException ex) {
     73  *           return;
     74  *         }
     75  *       }
     76  *     }
     77  *   }
     78  *
     79  *   public Solver(float[][] matrix) {
     80  *     data = matrix;
     81  *     N = matrix.length;
     82  *     barrier = new CyclicBarrier(N,
     83  *                                 new Runnable() {
     84  *                                   public void run() {
     85  *                                     mergeRows(...);
     86  *                                   }
     87  *                                 });
     88  *     for (int i = 0; i < N; ++i)
     89  *       new Thread(new Worker(i)).start();
     90  *
     91  *     waitUntilDone();
     92  *   }
     93  * }
     94  * </pre>
     95  * Here, each worker thread processes a row of the matrix then waits at the
     96  * barrier until all rows have been processed. When all rows are processed
     97  * the supplied {@link Runnable} barrier action is executed and merges the
     98  * rows. If the merger
     99  * determines that a solution has been found then <tt>done()</tt> will return
    100  * <tt>true</tt> and each worker will terminate.
    101  *
    102  * <p>If the barrier action does not rely on the parties being suspended when
    103  * it is executed, then any of the threads in the party could execute that
    104  * action when it is released. To facilitate this, each invocation of
    105  * {@link #await} returns the arrival index of that thread at the barrier.
    106  * You can then choose which thread should execute the barrier action, for
    107  * example:
    108  * <pre>  if (barrier.await() == 0) {
    109  *     // log the completion of this iteration
    110  *   }</pre>
    111  *
    112  * <p>The <tt>CyclicBarrier</tt> uses an all-or-none breakage model
    113  * for failed synchronization attempts: If a thread leaves a barrier
    114  * point prematurely because of interruption, failure, or timeout, all
    115  * other threads waiting at that barrier point will also leave
    116  * abnormally via {@link BrokenBarrierException} (or
    117  * {@link InterruptedException} if they too were interrupted at about
    118  * the same time).
    119  *
    120  * <p>Memory consistency effects: Actions in a thread prior to calling
    121  * {@code await()}
    122  * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
    123  * actions that are part of the barrier action, which in turn
    124  * <i>happen-before</i> actions following a successful return from the
    125  * corresponding {@code await()} in other threads.
    126  *
    127  * @since 1.5
    128  * @see CountDownLatch
    129  *
    130  * @author Doug Lea
    131  */
    132 public class CyclicBarrier {
    133     /**
    134      * Each use of the barrier is represented as a generation instance.
    135      * The generation changes whenever the barrier is tripped, or
    136      * is reset. There can be many generations associated with threads
    137      * using the barrier - due to the non-deterministic way the lock
    138      * may be allocated to waiting threads - but only one of these
    139      * can be active at a time (the one to which <tt>count</tt> applies)
    140      * and all the rest are either broken or tripped.
    141      * There need not be an active generation if there has been a break
    142      * but no subsequent reset.
    143      */
    144     private static class Generation {
    145         boolean broken = false;
    146     }
    147 
    148     /** The lock for guarding barrier entry */
    149     private final ReentrantLock lock = new ReentrantLock();
    150     /** Condition to wait on until tripped */
    151     private final Condition trip = lock.newCondition();
    152     /** The number of parties */
    153     private final int parties;
    154     /* The command to run when tripped */
    155     private final Runnable barrierCommand;
    156     /** The current generation */
    157     private Generation generation = new Generation();
    158 
    159     /**
    160      * Number of parties still waiting. Counts down from parties to 0
    161      * on each generation.  It is reset to parties on each new
    162      * generation or when broken.
    163      */
    164     private int count;
    165 
    166     /**
    167      * Updates state on barrier trip and wakes up everyone.
    168      * Called only while holding lock.
    169      */
    170     private void nextGeneration() {
    171         // signal completion of last generation
    172         trip.signalAll();
    173         // set up next generation
    174         count = parties;
    175         generation = new Generation();
    176     }
    177 
    178     /**
    179      * Sets current barrier generation as broken and wakes up everyone.
    180      * Called only while holding lock.
    181      */
    182     private void breakBarrier() {
    183         generation.broken = true;
    184         count = parties;
    185         trip.signalAll();
    186     }
    187 
    188     /**
    189      * Main barrier code, covering the various policies.
    190      */
    191     private int dowait(boolean timed, long nanos)
    192         throws InterruptedException, BrokenBarrierException,
    193                TimeoutException {
    194         final ReentrantLock lock = this.lock;
    195         lock.lock();
    196         try {
    197             final Generation g = generation;
    198 
    199             if (g.broken)
    200                 throw new BrokenBarrierException();
    201 
    202             if (Thread.interrupted()) {
    203                 breakBarrier();
    204                 throw new InterruptedException();
    205             }
    206 
    207            int index = --count;
    208            if (index == 0) {  // tripped
    209                boolean ranAction = false;
    210                try {
    211                    final Runnable command = barrierCommand;
    212                    if (command != null)
    213                        command.run();
    214                    ranAction = true;
    215                    nextGeneration();
    216                    return 0;
    217                } finally {
    218                    if (!ranAction)
    219                        breakBarrier();
    220                }
    221            }
    222 
    223             // loop until tripped, broken, interrupted, or timed out
    224             for (;;) {
    225                 try {
    226                     if (!timed)
    227                         trip.await();
    228                     else if (nanos > 0L)
    229                         nanos = trip.awaitNanos(nanos);
    230                 } catch (InterruptedException ie) {
    231                     if (g == generation && ! g.broken) {
    232                         breakBarrier();
    233                         throw ie;
    234                     } else {
    235                         // We're about to finish waiting even if we had not
    236                         // been interrupted, so this interrupt is deemed to
    237                         // "belong" to subsequent execution.
    238                         Thread.currentThread().interrupt();
    239                     }
    240                 }
    241 
    242                 if (g.broken)
    243                     throw new BrokenBarrierException();
    244 
    245                 if (g != generation)
    246                     return index;
    247 
    248                 if (timed && nanos <= 0L) {
    249                     breakBarrier();
    250                     throw new TimeoutException();
    251                 }
    252             }
    253         } finally {
    254             lock.unlock();
    255         }
    256     }
    257 
    258     /**
    259      * Creates a new <tt>CyclicBarrier</tt> that will trip when the
    260      * given number of parties (threads) are waiting upon it, and which
    261      * will execute the given barrier action when the barrier is tripped,
    262      * performed by the last thread entering the barrier.
    263      *
    264      * @param parties the number of threads that must invoke {@link #await}
    265      *        before the barrier is tripped
    266      * @param barrierAction the command to execute when the barrier is
    267      *        tripped, or {@code null} if there is no action
    268      * @throws IllegalArgumentException if {@code parties} is less than 1
    269      */
    270     public CyclicBarrier(int parties, Runnable barrierAction) {
    271         if (parties <= 0) throw new IllegalArgumentException();
    272         this.parties = parties;
    273         this.count = parties;
    274         this.barrierCommand = barrierAction;
    275     }
    276 
    277     /**
    278      * Creates a new <tt>CyclicBarrier</tt> that will trip when the
    279      * given number of parties (threads) are waiting upon it, and
    280      * does not perform a predefined action when the barrier is tripped.
    281      *
    282      * @param parties the number of threads that must invoke {@link #await}
    283      *        before the barrier is tripped
    284      * @throws IllegalArgumentException if {@code parties} is less than 1
    285      */
    286     public CyclicBarrier(int parties) {
    287         this(parties, null);
    288     }
    289 
    290     /**
    291      * Returns the number of parties required to trip this barrier.
    292      *
    293      * @return the number of parties required to trip this barrier
    294      */
    295     public int getParties() {
    296         return parties;
    297     }
    298 
    299     /**
    300      * Waits until all {@linkplain #getParties parties} have invoked
    301      * <tt>await</tt> on this barrier.
    302      *
    303      * <p>If the current thread is not the last to arrive then it is
    304      * disabled for thread scheduling purposes and lies dormant until
    305      * one of the following things happens:
    306      * <ul>
    307      * <li>The last thread arrives; or
    308      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    309      * the current thread; or
    310      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    311      * one of the other waiting threads; or
    312      * <li>Some other thread times out while waiting for barrier; or
    313      * <li>Some other thread invokes {@link #reset} on this barrier.
    314      * </ul>
    315      *
    316      * <p>If the current thread:
    317      * <ul>
    318      * <li>has its interrupted status set on entry to this method; or
    319      * <li>is {@linkplain Thread#interrupt interrupted} while waiting
    320      * </ul>
    321      * then {@link InterruptedException} is thrown and the current thread's
    322      * interrupted status is cleared.
    323      *
    324      * <p>If the barrier is {@link #reset} while any thread is waiting,
    325      * or if the barrier {@linkplain #isBroken is broken} when
    326      * <tt>await</tt> is invoked, or while any thread is waiting, then
    327      * {@link BrokenBarrierException} is thrown.
    328      *
    329      * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting,
    330      * then all other waiting threads will throw
    331      * {@link BrokenBarrierException} and the barrier is placed in the broken
    332      * state.
    333      *
    334      * <p>If the current thread is the last thread to arrive, and a
    335      * non-null barrier action was supplied in the constructor, then the
    336      * current thread runs the action before allowing the other threads to
    337      * continue.
    338      * If an exception occurs during the barrier action then that exception
    339      * will be propagated in the current thread and the barrier is placed in
    340      * the broken state.
    341      *
    342      * @return the arrival index of the current thread, where index
    343      *         <tt>{@link #getParties()} - 1</tt> indicates the first
    344      *         to arrive and zero indicates the last to arrive
    345      * @throws InterruptedException if the current thread was interrupted
    346      *         while waiting
    347      * @throws BrokenBarrierException if <em>another</em> thread was
    348      *         interrupted or timed out while the current thread was
    349      *         waiting, or the barrier was reset, or the barrier was
    350      *         broken when {@code await} was called, or the barrier
    351      *         action (if present) failed due an exception.
    352      */
    353     public int await() throws InterruptedException, BrokenBarrierException {
    354         try {
    355             return dowait(false, 0L);
    356         } catch (TimeoutException toe) {
    357             throw new Error(toe); // cannot happen;
    358         }
    359     }
    360 
    361     /**
    362      * Waits until all {@linkplain #getParties parties} have invoked
    363      * <tt>await</tt> on this barrier, or the specified waiting time elapses.
    364      *
    365      * <p>If the current thread is not the last to arrive then it is
    366      * disabled for thread scheduling purposes and lies dormant until
    367      * one of the following things happens:
    368      * <ul>
    369      * <li>The last thread arrives; or
    370      * <li>The specified timeout elapses; or
    371      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    372      * the current thread; or
    373      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    374      * one of the other waiting threads; or
    375      * <li>Some other thread times out while waiting for barrier; or
    376      * <li>Some other thread invokes {@link #reset} on this barrier.
    377      * </ul>
    378      *
    379      * <p>If the current thread:
    380      * <ul>
    381      * <li>has its interrupted status set on entry to this method; or
    382      * <li>is {@linkplain Thread#interrupt interrupted} while waiting
    383      * </ul>
    384      * then {@link InterruptedException} is thrown and the current thread's
    385      * interrupted status is cleared.
    386      *
    387      * <p>If the specified waiting time elapses then {@link TimeoutException}
    388      * is thrown. If the time is less than or equal to zero, the
    389      * method will not wait at all.
    390      *
    391      * <p>If the barrier is {@link #reset} while any thread is waiting,
    392      * or if the barrier {@linkplain #isBroken is broken} when
    393      * <tt>await</tt> is invoked, or while any thread is waiting, then
    394      * {@link BrokenBarrierException} is thrown.
    395      *
    396      * <p>If any thread is {@linkplain Thread#interrupt interrupted} while
    397      * waiting, then all other waiting threads will throw {@link
    398      * BrokenBarrierException} and the barrier is placed in the broken
    399      * state.
    400      *
    401      * <p>If the current thread is the last thread to arrive, and a
    402      * non-null barrier action was supplied in the constructor, then the
    403      * current thread runs the action before allowing the other threads to
    404      * continue.
    405      * If an exception occurs during the barrier action then that exception
    406      * will be propagated in the current thread and the barrier is placed in
    407      * the broken state.
    408      *
    409      * @param timeout the time to wait for the barrier
    410      * @param unit the time unit of the timeout parameter
    411      * @return the arrival index of the current thread, where index
    412      *         <tt>{@link #getParties()} - 1</tt> indicates the first
    413      *         to arrive and zero indicates the last to arrive
    414      * @throws InterruptedException if the current thread was interrupted
    415      *         while waiting
    416      * @throws TimeoutException if the specified timeout elapses
    417      * @throws BrokenBarrierException if <em>another</em> thread was
    418      *         interrupted or timed out while the current thread was
    419      *         waiting, or the barrier was reset, or the barrier was broken
    420      *         when {@code await} was called, or the barrier action (if
    421      *         present) failed due an exception
    422      */
    423     public int await(long timeout, TimeUnit unit)
    424         throws InterruptedException,
    425                BrokenBarrierException,
    426                TimeoutException {
    427         return dowait(true, unit.toNanos(timeout));
    428     }
    429 
    430     /**
    431      * Queries if this barrier is in a broken state.
    432      *
    433      * @return {@code true} if one or more parties broke out of this
    434      *         barrier due to interruption or timeout since
    435      *         construction or the last reset, or a barrier action
    436      *         failed due to an exception; {@code false} otherwise.
    437      */
    438     public boolean isBroken() {
    439         final ReentrantLock lock = this.lock;
    440         lock.lock();
    441         try {
    442             return generation.broken;
    443         } finally {
    444             lock.unlock();
    445         }
    446     }
    447 
    448     /**
    449      * Resets the barrier to its initial state.  If any parties are
    450      * currently waiting at the barrier, they will return with a
    451      * {@link BrokenBarrierException}. Note that resets <em>after</em>
    452      * a breakage has occurred for other reasons can be complicated to
    453      * carry out; threads need to re-synchronize in some other way,
    454      * and choose one to perform the reset.  It may be preferable to
    455      * instead create a new barrier for subsequent use.
    456      */
    457     public void reset() {
    458         final ReentrantLock lock = this.lock;
    459         lock.lock();
    460         try {
    461             breakBarrier();   // break the current generation
    462             nextGeneration(); // start a new generation
    463         } finally {
    464             lock.unlock();
    465         }
    466     }
    467 
    468     /**
    469      * Returns the number of parties currently waiting at the barrier.
    470      * This method is primarily useful for debugging and assertions.
    471      *
    472      * @return the number of parties currently blocked in {@link #await}
    473      */
    474     public int getNumberWaiting() {
    475         final ReentrantLock lock = this.lock;
    476         lock.lock();
    477         try {
    478             return parties - count;
    479         } finally {
    480             lock.unlock();
    481         }
    482     }
    483 }
    View Code

    CyclicBarrier是通过ReentrantLock(独占锁)和Condition来实现的。下面,我们分析CyclicBarrier中3个核心函数: 构造函数, await()作出分析。

    1. 构造函数

    CyclicBarrier的构造函数共2个:CyclicBarrier 和 CyclicBarrier(int parties, Runnable barrierAction)。第1个构造函数是调用第2个构造函数来实现的,下面第2个构造函数的源码。

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        // parties表示“必须同时到达barrier的线程个数”。
        this.parties = parties;
        // count表示“处在等待状态的线程个数”。
        this.count = parties;
        // barrierCommand表示“parties个线程到达barrier时,会执行的动作”。
        this.barrierCommand = barrierAction;
    }

    2. 等待函数

    CyclicBarrier.java中await()方法如下:

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            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.lock();
        try {
            // 保存“当前的generation”
            final Generation g = generation;
    
            // 若“当前generation已损坏”,则抛出异常。
            if (g.broken)
                throw new BrokenBarrierException();
    
            // 如果当前线程被中断,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
    
           // 将“count计数器”-1
           int index = --count;
           // 如果index=0,则意味着“有parties个线程到达barrier”。
           if (index == 0) {  // tripped
               boolean ranAction = false;
               try {
                   // 如果barrierCommand不为null,则执行该动作。
                   final Runnable command = barrierCommand;
                   if (command != null)
                       command.run();
                   ranAction = true;
                   // 唤醒所有等待线程,并更新generation。
                   nextGeneration();
                   return 0;
               } finally {
                   if (!ranAction)
                       breakBarrier();
               }
           }
    
            // 当前线程一直阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,
            // 当前线程才继续执行。
            for (;;) {
                try {
                    // 如果不是“超时等待”,则调用awati()进行等待;否则,调用awaitNanos()进行等待。
                    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();
                    }
                }
    
                // 如果“当前generation已经损坏”,则抛出异常。
                if (g.broken)
                    throw new BrokenBarrierException();
    
                // 如果“generation已经换代”,则返回index。
                if (g != generation)
                    return index;
    
                // 如果是“超时等待”,并且时间已到,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            // 释放“独占锁(lock)”
            lock.unlock();
        }
    }

    说明:dowait()的作用就是让当前线程阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,当前线程才继续执行。
    (01) generation是CyclicBarrier的一个成员遍历,它的定义如下:

    private Generation generation = new Generation();
    
    private static class Generation {
        boolean broken = false;
    }

    在CyclicBarrier中,同一批的线程属于同一代,即同一个Generation;CyclicBarrier中通过generation对象,记录属于哪一代。
    当有parties个线程到达barrier,generation就会被更新换代。

    (02) 如果当前线程被中断,即Thread.interrupted()为true;则通过breakBarrier()终止CyclicBarrier。breakBarrier()的源码如下:

    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }

    breakBarrier()会设置当前中断标记broken为true,意味着“将该Generation中断”;同时,设置count=parties,即重新初始化count;最后,通过signalAll()唤醒CyclicBarrier上所有的等待线程。

    (03) 将“count计数器”-1,即--count;然后判断是不是“有parties个线程到达barrier”,即index是不是为0。
    当index=0时,如果barrierCommand不为null,则执行该barrierCommand,barrierCommand就是我们创建CyclicBarrier时,传入的Runnable对象。然后,调用nextGeneration()进行换代工作,nextGeneration()的源码如下:

    private void nextGeneration() {
        trip.signalAll();
        count = parties;
        generation = new Generation();
    }

    首先,它会调用signalAll()唤醒CyclicBarrier上所有的等待线程;接着,重新初始化count;最后,更新generation的值。

    (04) 在for(;;)循环中。timed是用来表示当前是不是“超时等待”线程。如果不是,则通过trip.await()进行等待;否则,调用awaitNanos()进行超时等待。

     

    CyclicBarrier的使用示例

    示例1
    新建5个线程,这5个线程达到一定的条件时,它们才继续往后运行。

     1 import java.util.concurrent.CyclicBarrier;
     2 import java.util.concurrent.BrokenBarrierException;
     3 
     4 public class CyclicBarrierTest1 {
     5 
     6     private static int SIZE = 5;
     7     private static CyclicBarrier cb;
     8     public static void main(String[] args) {
     9 
    10         cb = new CyclicBarrier(SIZE);
    11 
    12         // 新建5个任务
    13         for(int i=0; i<SIZE; i++)
    14             new InnerThread().start();
    15     }
    16 
    17     static class InnerThread extends Thread{
    18         public void run() {
    19             try {
    20                 System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
    21 
    22                 // 将cb的参与者数量加1
    23                 cb.await();
    24 
    25                 // cb的参与者数量等于5时,才继续往后执行
    26                 System.out.println(Thread.currentThread().getName() + " continued.");
    27             } catch (BrokenBarrierException e) {
    28                 e.printStackTrace();
    29             } catch (InterruptedException e) {
    30                 e.printStackTrace();
    31             }
    32         }
    33     }
    34 }

    运行结果

    Thread-1 wait for CyclicBarrier.
    Thread-2 wait for CyclicBarrier.
    Thread-3 wait for CyclicBarrier.
    Thread-4 wait for CyclicBarrier.
    Thread-0 wait for CyclicBarrier.
    Thread-0 continued.
    Thread-4 continued.
    Thread-2 continued.
    Thread-3 continued.
    Thread-1 continued.

    结果说明:主线程中新建了5个线程,所有的这些线程都调用cb.await()等待。所有这些线程一直等待,直到cb中所有线程都达到barrier时,这些线程才继续运行!

    示例2

    新建5个线程,当这5个线程达到一定的条件时,执行某项任务。

     1 import java.util.concurrent.CyclicBarrier;
     2 import java.util.concurrent.BrokenBarrierException;
     3 
     4 public class CyclicBarrierTest2 {
     5 
     6     private static int SIZE = 5;
     7     private static CyclicBarrier cb;
     8     public static void main(String[] args) {
     9 
    10         cb = new CyclicBarrier(SIZE, new Runnable () {
    11             public void run() {
    12                 System.out.println("CyclicBarrier's parties is: "+ cb.getParties());
    13             }
    14         });
    15 
    16         // 新建5个任务
    17         for(int i=0; i<SIZE; i++)
    18             new InnerThread().start();
    19     }
    20 
    21     static class InnerThread extends Thread{
    22         public void run() {
    23             try {
    24                 System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
    25 
    26                 // 将cb的参与者数量加1
    27                 cb.await();
    28 
    29                 // cb的参与者数量等于5时,才继续往后执行
    30                 System.out.println(Thread.currentThread().getName() + " continued.");
    31             } catch (BrokenBarrierException e) {
    32                 e.printStackTrace();
    33             } catch (InterruptedException e) {
    34                 e.printStackTrace();
    35             }
    36         }
    37     }
    38 }

    运行结果

    Thread-1 wait for CyclicBarrier.
    Thread-2 wait for CyclicBarrier.
    Thread-3 wait for CyclicBarrier.
    Thread-4 wait for CyclicBarrier.
    Thread-0 wait for CyclicBarrier.
    CyclicBarrier's parties is: 5
    Thread-0 continued.
    Thread-4 continued.
    Thread-2 continued.
    Thread-3 continued.
    Thread-1 continued.

    结果说明:主线程中新建了5个线程,所有的这些线程都调用cb.await()等待。所有这些线程一直等待,直到cb中所有线程都达到barrier时,执行新建cb时注册的Runnable任务。


    更多内容

    1. Java多线程系列--“JUC锁”01之 框架 

    2. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock 

    3. Java多线程系列--“JUC锁”03之 公平锁(一) 

    4. Java多线程系列--“JUC锁”04之 公平锁(二)

    5. Java多线程系列--“JUC锁”05之 非公平锁

    6. Java多线程系列--“JUC锁”06之 Condition条件

    7. Java多线程系列--“JUC锁”07之 LockSupport 

    8. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

    9. Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例

    10. Java多线程系列目录(共xx篇)

  • 相关阅读:
    Palindrome Linked List 解答
    Word Break II 解答
    Array vs Linked List
    Reverse Linked List II 解答
    Calculate Number Of Islands And Lakes 解答
    Sqrt(x) 解答
    Find Median from Data Stream 解答
    Majority Element II 解答
    Binary Search Tree DFS Template
    188. Best Time to Buy and Sell Stock IV
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3533995.html
Copyright © 2020-2023  润新知