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-16632 * Expert Group and released to the public domain, as explained at33 *http://creativecommons.org/publicdomain/zero/1.0/
34 */
35
36 packagejava.util.concurrent;37 import java.util.concurrent.locks.*;38
39 /**
40 * A synchronization aid that allows a set of threads to all wait for41 * each other to reach a common barrier point. CyclicBarriers are42 * useful in programs involving a fixed sized party of threads that43 * must occasionally wait for each other. The barrier is called44 * cyclic because it can be re-used after the waiting threads45 * are released.46 *47 *
A CyclicBarrier supports an optional {@linkRunnable} command48 * that is run once per barrier point, after the last thread in the party49 * arrives, but before any threads are released.50 * This barrier action is useful51 * for updating shared-state before any of the parties continue.52 *53 *
Sample usage: Here is an example of54 * using a barrier in a parallel decomposition design:55 *
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 *95 * Here, each worker thread processes a row of the matrix then waits at the96 * barrier until all rows have been processed. When all rows are processed97 * the supplied {@linkRunnable} barrier action is executed and merges the98 * rows. If the merger99 * determines that a solution has been found then done() will return100 * true and each worker will terminate.101 *102 *
If the barrier action does not rely on the parties being suspended when103 * it is executed, then any of the threads in the party could execute that104 * action when it is released. To facilitate this, each invocation of105 * {@link#await} returns the arrival index of that thread at the barrier.106 * You can then choose which thread should execute the barrier action, for107 * example:108 *
if (barrier.await() == 0) {109 * // log the completion of this iteration110 * }111 *112 *
The CyclicBarrier uses an all-or-none breakage model113 * for failed synchronization attempts: If a thread leaves a barrier114 * point prematurely because of interruption, failure, or timeout, all115 * other threads waiting at that barrier point will also leave116 * abnormally via {@linkBrokenBarrierException} (or117 * {@linkInterruptedException} if they too were interrupted at about118 * the same time).119 *120 *
Memory consistency effects: Actions in a thread prior to calling121 * {@codeawait()}122 * happen-before123 * actions that are part of the barrier action, which in turn124 * happen-before actions following a successful return from the125 * corresponding {@codeawait()} in other threads.126 *127 *@since1.5128 *@seeCountDownLatch129 *130 *@authorDoug Lea131 */
132 public classCyclicBarrier {133 /**
134 * Each use of the barrier is represented as a generation instance.135 * The generation changes whenever the barrier is tripped, or136 * is reset. There can be many generations associated with threads137 * using the barrier - due to the non-deterministic way the lock138 * may be allocated to waiting threads - but only one of these139 * can be active at a time (the one to which count applies)140 * and all the rest are either broken or tripped.141 * There need not be an active generation if there has been a break142 * but no subsequent reset.143 */
144 private static classGeneration {145 boolean broken = false;146 }147
148 /**The lock for guarding barrier entry*/
149 private final ReentrantLock lock = newReentrantLock();150 /**Condition to wait on until tripped*/
151 private final Condition trip =lock.newCondition();152 /**The number of parties*/
153 private final intparties;154 /*The command to run when tripped*/
155 private finalRunnable barrierCommand;156 /**The current generation*/
157 private Generation generation = newGeneration();158
159 /**
160 * Number of parties still waiting. Counts down from parties to 0161 * on each generation. It is reset to parties on each new162 * generation or when broken.163 */
164 private intcount;165
166 /**
167 * Updates state on barrier trip and wakes up everyone.168 * Called only while holding lock.169 */
170 private voidnextGeneration() {171 //signal completion of last generation
172 trip.signalAll();173 //set up next generation
174 count =parties;175 generation = newGeneration();176 }177
178 /**
179 * Sets current barrier generation as broken and wakes up everyone.180 * Called only while holding lock.181 */
182 private voidbreakBarrier() {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, longnanos)192 throwsInterruptedException, 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 newBrokenBarrierException();201
202 if(Thread.interrupted()) {203 breakBarrier();204 throw newInterruptedException();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 throwie;234 } else{235 //We're about to finish waiting even if we had not236 //been interrupted, so this interrupt is deemed to237 //"belong" to subsequent execution.
238 Thread.currentThread().interrupt();239 }240 }241
242 if(g.broken)243 throw newBrokenBarrierException();244
245 if (g !=generation)246 returnindex;247
248 if (timed && nanos <= 0L) {249 breakBarrier();250 throw newTimeoutException();251 }252 }253 } finally{254 lock.unlock();255 }256 }257
258 /**
259 * Creates a new CyclicBarrier that will trip when the260 * given number of parties (threads) are waiting upon it, and which261 * will execute the given barrier action when the barrier is tripped,262 * performed by the last thread entering the barrier.263 *264 *@paramparties the number of threads that must invoke {@link#await}265 * before the barrier is tripped266 *@parambarrierAction the command to execute when the barrier is267 * tripped, or {@codenull} if there is no action268 *@throwsIllegalArgumentException if {@codeparties} is less than 1269 */
270 public CyclicBarrier(intparties, Runnable barrierAction) {271 if (parties <= 0) throw newIllegalArgumentException();272 this.parties =parties;273 this.count =parties;274 this.barrierCommand =barrierAction;275 }276
277 /**
278 * Creates a new CyclicBarrier that will trip when the279 * given number of parties (threads) are waiting upon it, and280 * does not perform a predefined action when the barrier is tripped.281 *282 *@paramparties the number of threads that must invoke {@link#await}283 * before the barrier is tripped284 *@throwsIllegalArgumentException if {@codeparties} is less than 1285 */
286 public CyclicBarrier(intparties) {287 this(parties, null);288 }289
290 /**
291 * Returns the number of parties required to trip this barrier.292 *293 *@returnthe number of parties required to trip this barrier294 */
295 public intgetParties() {296 returnparties;297 }298
299 /**
300 * Waits until all {@linkplain#getParties parties} have invoked301 * await on this barrier.302 *303 *
If the current thread is not the last to arrive then it is304 * disabled for thread scheduling purposes and lies dormant until305 * one of the following things happens:306 *
- 307 *
- The last thread arrives; or308 *
- Some other thread {@linkplainThread#interrupt interrupts}309 * the current thread; or310 *
- Some other thread {@linkplainThread#interrupt interrupts}311 * one of the other waiting threads; or312 *
- Some other thread times out while waiting for barrier; or313 *
- Some other thread invokes {@link#reset} on this barrier.314 *
If the current thread:317 *
- 318 *
- has its interrupted status set on entry to this method; or319 *
- is {@linkplainThread#interrupt interrupted} while waiting320 *
If the barrier is {@link#reset} while any thread is waiting,325 * or if the barrier {@linkplain#isBroken is broken} when326 * await is invoked, or while any thread is waiting, then327 * {@linkBrokenBarrierException} is thrown.328 *329 *
If any thread is {@linkplainThread#interrupt interrupted} while waiting,330 * then all other waiting threads will throw331 * {@linkBrokenBarrierException} and the barrier is placed in the broken332 * state.333 *334 *
If the current thread is the last thread to arrive, and a335 * non-null barrier action was supplied in the constructor, then the336 * current thread runs the action before allowing the other threads to337 * continue.338 * If an exception occurs during the barrier action then that exception339 * will be propagated in the current thread and the barrier is placed in340 * the broken state.341 *342 *@returnthe arrival index of the current thread, where index343 * {@link#getParties()} - 1 indicates the first344 * to arrive and zero indicates the last to arrive345 *@throwsInterruptedException if the current thread was interrupted346 * while waiting347 *@throwsBrokenBarrierException if another thread was348 * interrupted or timed out while the current thread was349 * waiting, or the barrier was reset, or the barrier was350 * broken when {@codeawait} was called, or the barrier351 * action (if present) failed due an exception.352 */
353 public int await() throwsInterruptedException, 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 invoked363 * await on this barrier, or the specified waiting time elapses.364 *365 *
If the current thread is not the last to arrive then it is366 * disabled for thread scheduling purposes and lies dormant until367 * one of the following things happens:368 *
- 369 *
- The last thread arrives; or370 *
- The specified timeout elapses; or371 *
- Some other thread {@linkplainThread#interrupt interrupts}372 * the current thread; or373 *
- Some other thread {@linkplainThread#interrupt interrupts}374 * one of the other waiting threads; or375 *
- Some other thread times out while waiting for barrier; or376 *
- Some other thread invokes {@link#reset} on this barrier.377 *
If the current thread:380 *
- 381 *
- has its interrupted status set on entry to this method; or382 *
- is {@linkplainThread#interrupt interrupted} while waiting383 *
If the specified waiting time elapses then {@linkTimeoutException}388 * is thrown. If the time is less than or equal to zero, the389 * method will not wait at all.390 *391 *
If the barrier is {@link#reset} while any thread is waiting,392 * or if the barrier {@linkplain#isBroken is broken} when393 * await is invoked, or while any thread is waiting, then394 * {@linkBrokenBarrierException} is thrown.395 *396 *
If any thread is {@linkplainThread#interrupt interrupted} while397 * waiting, then all other waiting threads will throw {@link
398 * BrokenBarrierException} and the barrier is placed in the broken399 * state.400 *401 *
If the current thread is the last thread to arrive, and a402 * non-null barrier action was supplied in the constructor, then the403 * current thread runs the action before allowing the other threads to404 * continue.405 * If an exception occurs during the barrier action then that exception406 * will be propagated in the current thread and the barrier is placed in407 * the broken state.408 *409 *@paramtimeout the time to wait for the barrier410 *@paramunit the time unit of the timeout parameter411 *@returnthe arrival index of the current thread, where index412 * {@link#getParties()} - 1 indicates the first413 * to arrive and zero indicates the last to arrive414 *@throwsInterruptedException if the current thread was interrupted415 * while waiting416 *@throwsTimeoutException if the specified timeout elapses417 *@throwsBrokenBarrierException if another thread was418 * interrupted or timed out while the current thread was419 * waiting, or the barrier was reset, or the barrier was broken420 * when {@codeawait} was called, or the barrier action (if421 * present) failed due an exception422 */
423 public int await(longtimeout, TimeUnit unit)424 throwsInterruptedException,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{@codetrue} if one or more parties broke out of this434 * barrier due to interruption or timeout since435 * construction or the last reset, or a barrier action436 * failed due to an exception; {@codefalse} otherwise.437 */
438 public booleanisBroken() {439 final ReentrantLock lock = this.lock;440 lock.lock();441 try{442 returngeneration.broken;443 } finally{444 lock.unlock();445 }446 }447
448 /**
449 * Resets the barrier to its initial state. If any parties are450 * currently waiting at the barrier, they will return with a451 * {@linkBrokenBarrierException}. Note that resets after452 * a breakage has occurred for other reasons can be complicated to453 * carry out; threads need to re-synchronize in some other way,454 * and choose one to perform the reset. It may be preferable to455 * instead create a new barrier for subsequent use.456 */
457 public voidreset() {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 *@returnthe number of parties currently blocked in {@link#await}473 */
474 public intgetNumberWaiting() {475 final ReentrantLock lock = this.lock;476 lock.lock();477 try{478 return parties -count;479 } finally{480 lock.unlock();481 }482 }483 }