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

 

概要

本章介绍JUC包中的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函数列表

Java多线程系列--“JUC锁”10之 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()
将屏障重置为其初始状态。
Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

 

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个构造函数的源码。

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

 

2. 等待函数

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

Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen;
    }
}
Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

说明:await()是通过dowait()实现的。

 

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

说明: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个线程达到一定的条件时,它们才继续往后运行。

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

运行结果

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

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

 

示例2

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

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

运行结果

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

结果说明:主线程中新建了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篇)

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

上一篇:【比赛题解】CSP2021 提高组题解


下一篇:flutter学习笔记(二)