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类图如下:

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

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

 

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

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

Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
 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篇)

 

你可能感兴趣的:(Cyclicbarrier)