1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 * Other contributors include Andrew Wright, Jeffrey Hayes, 6 * Pat Fisher, Mike Judd. 7 */ 8 9 package jsr166; 10 11 import static java.util.concurrent.TimeUnit.MILLISECONDS; 12 13 import java.util.concurrent.BrokenBarrierException; 14 import java.util.concurrent.CountDownLatch; 15 import java.util.concurrent.CyclicBarrier; 16 import java.util.concurrent.TimeoutException; 17 import java.util.concurrent.atomic.AtomicBoolean; 18 19 import junit.framework.Test; 20 import junit.framework.TestSuite; 21 22 public class CyclicBarrierTest extends JSR166TestCase { 23 // android-note: Removed because the CTS runner does a bad job of 24 // retrying tests that have suite() declarations. 25 // 26 // public static void main(String[] args) { 27 // main(suite(), args); 28 // } 29 // public static Test suite() { 30 // return new TestSuite(CyclicBarrierTest.class); 31 // } 32 33 private volatile int countAction; 34 private class MyAction implements Runnable { 35 public void run() { ++countAction; } 36 } 37 38 /** 39 * Spin-waits till the number of waiters == numberOfWaiters. 40 */ 41 void awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters) { 42 long startTime = System.nanoTime(); 43 while (barrier.getNumberWaiting() != numberOfWaiters) { 44 if (millisElapsedSince(startTime) > LONG_DELAY_MS) 45 fail("timed out"); 46 Thread.yield(); 47 } 48 } 49 50 /** 51 * Creating with negative parties throws IAE 52 */ 53 public void testConstructor1() { 54 try { 55 new CyclicBarrier(-1, (Runnable)null); 56 shouldThrow(); 57 } catch (IllegalArgumentException success) {} 58 } 59 60 /** 61 * Creating with negative parties and no action throws IAE 62 */ 63 public void testConstructor2() { 64 try { 65 new CyclicBarrier(-1); 66 shouldThrow(); 67 } catch (IllegalArgumentException success) {} 68 } 69 70 /** 71 * getParties returns the number of parties given in constructor 72 */ 73 public void testGetParties() { 74 CyclicBarrier b = new CyclicBarrier(2); 75 assertEquals(2, b.getParties()); 76 assertEquals(0, b.getNumberWaiting()); 77 } 78 79 /** 80 * A 1-party barrier triggers after single await 81 */ 82 public void testSingleParty() throws Exception { 83 CyclicBarrier b = new CyclicBarrier(1); 84 assertEquals(1, b.getParties()); 85 assertEquals(0, b.getNumberWaiting()); 86 b.await(); 87 b.await(); 88 assertEquals(0, b.getNumberWaiting()); 89 } 90 91 /** 92 * The supplied barrier action is run at barrier 93 */ 94 public void testBarrierAction() throws Exception { 95 countAction = 0; 96 CyclicBarrier b = new CyclicBarrier(1, new MyAction()); 97 assertEquals(1, b.getParties()); 98 assertEquals(0, b.getNumberWaiting()); 99 b.await(); 100 b.await(); 101 assertEquals(0, b.getNumberWaiting()); 102 assertEquals(2, countAction); 103 } 104 105 /** 106 * A 2-party/thread barrier triggers after both threads invoke await 107 */ 108 public void testTwoParties() throws Exception { 109 final CyclicBarrier b = new CyclicBarrier(2); 110 Thread t = newStartedThread(new CheckedRunnable() { 111 public void realRun() throws Exception { 112 b.await(); 113 b.await(); 114 b.await(); 115 b.await(); 116 }}); 117 118 b.await(); 119 b.await(); 120 b.await(); 121 b.await(); 122 awaitTermination(t); 123 } 124 125 /** 126 * An interruption in one party causes others waiting in await to 127 * throw BrokenBarrierException 128 */ 129 public void testAwait1_Interrupted_BrokenBarrier() { 130 final CyclicBarrier c = new CyclicBarrier(3); 131 final CountDownLatch pleaseInterrupt = new CountDownLatch(2); 132 Thread t1 = new ThreadShouldThrow(InterruptedException.class) { 133 public void realRun() throws Exception { 134 pleaseInterrupt.countDown(); 135 c.await(); 136 }}; 137 Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { 138 public void realRun() throws Exception { 139 pleaseInterrupt.countDown(); 140 c.await(); 141 }}; 142 143 t1.start(); 144 t2.start(); 145 await(pleaseInterrupt); 146 t1.interrupt(); 147 awaitTermination(t1); 148 awaitTermination(t2); 149 } 150 151 /** 152 * An interruption in one party causes others waiting in timed await to 153 * throw BrokenBarrierException 154 */ 155 public void testAwait2_Interrupted_BrokenBarrier() throws Exception { 156 final CyclicBarrier c = new CyclicBarrier(3); 157 final CountDownLatch pleaseInterrupt = new CountDownLatch(2); 158 Thread t1 = new ThreadShouldThrow(InterruptedException.class) { 159 public void realRun() throws Exception { 160 pleaseInterrupt.countDown(); 161 c.await(LONG_DELAY_MS, MILLISECONDS); 162 }}; 163 Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { 164 public void realRun() throws Exception { 165 pleaseInterrupt.countDown(); 166 c.await(LONG_DELAY_MS, MILLISECONDS); 167 }}; 168 169 t1.start(); 170 t2.start(); 171 await(pleaseInterrupt); 172 t1.interrupt(); 173 awaitTermination(t1); 174 awaitTermination(t2); 175 } 176 177 /** 178 * A timeout in timed await throws TimeoutException 179 */ 180 public void testAwait3_TimeoutException() throws InterruptedException { 181 final CyclicBarrier c = new CyclicBarrier(2); 182 Thread t = newStartedThread(new CheckedRunnable() { 183 public void realRun() throws Exception { 184 long startTime = System.nanoTime(); 185 try { 186 c.await(timeoutMillis(), MILLISECONDS); 187 shouldThrow(); 188 } catch (TimeoutException success) {} 189 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 190 }}); 191 192 awaitTermination(t); 193 } 194 195 /** 196 * A timeout in one party causes others waiting in timed await to 197 * throw BrokenBarrierException 198 */ 199 public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException { 200 final CyclicBarrier c = new CyclicBarrier(3); 201 Thread t1 = newStartedThread(new CheckedRunnable() { 202 public void realRun() throws Exception { 203 try { 204 c.await(LONG_DELAY_MS, MILLISECONDS); 205 shouldThrow(); 206 } catch (BrokenBarrierException success) {} 207 }}); 208 Thread t2 = newStartedThread(new CheckedRunnable() { 209 public void realRun() throws Exception { 210 awaitNumberWaiting(c, 1); 211 long startTime = System.nanoTime(); 212 try { 213 c.await(timeoutMillis(), MILLISECONDS); 214 shouldThrow(); 215 } catch (TimeoutException success) {} 216 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 217 }}); 218 219 awaitTermination(t1); 220 awaitTermination(t2); 221 } 222 223 /** 224 * A timeout in one party causes others waiting in await to 225 * throw BrokenBarrierException 226 */ 227 public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException { 228 final CyclicBarrier c = new CyclicBarrier(3); 229 Thread t1 = newStartedThread(new CheckedRunnable() { 230 public void realRun() throws Exception { 231 try { 232 c.await(); 233 shouldThrow(); 234 } catch (BrokenBarrierException success) {} 235 }}); 236 Thread t2 = newStartedThread(new CheckedRunnable() { 237 public void realRun() throws Exception { 238 awaitNumberWaiting(c, 1); 239 long startTime = System.nanoTime(); 240 try { 241 c.await(timeoutMillis(), MILLISECONDS); 242 shouldThrow(); 243 } catch (TimeoutException success) {} 244 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 245 }}); 246 247 awaitTermination(t1); 248 awaitTermination(t2); 249 } 250 251 /** 252 * A reset of an active barrier causes waiting threads to throw 253 * BrokenBarrierException 254 */ 255 public void testReset_BrokenBarrier() throws InterruptedException { 256 final CyclicBarrier c = new CyclicBarrier(3); 257 final CountDownLatch pleaseReset = new CountDownLatch(2); 258 Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { 259 public void realRun() throws Exception { 260 pleaseReset.countDown(); 261 c.await(); 262 }}; 263 Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { 264 public void realRun() throws Exception { 265 pleaseReset.countDown(); 266 c.await(); 267 }}; 268 269 t1.start(); 270 t2.start(); 271 await(pleaseReset); 272 273 awaitNumberWaiting(c, 2); 274 c.reset(); 275 awaitTermination(t1); 276 awaitTermination(t2); 277 } 278 279 /** 280 * A reset before threads enter barrier does not throw 281 * BrokenBarrierException 282 */ 283 public void testReset_NoBrokenBarrier() throws Exception { 284 final CyclicBarrier c = new CyclicBarrier(3); 285 c.reset(); 286 287 Thread t1 = newStartedThread(new CheckedRunnable() { 288 public void realRun() throws Exception { 289 c.await(); 290 }}); 291 Thread t2 = newStartedThread(new CheckedRunnable() { 292 public void realRun() throws Exception { 293 c.await(); 294 }}); 295 296 c.await(); 297 awaitTermination(t1); 298 awaitTermination(t2); 299 } 300 301 /** 302 * All threads block while a barrier is broken. 303 */ 304 public void testReset_Leakage() throws InterruptedException { 305 final CyclicBarrier c = new CyclicBarrier(2); 306 final AtomicBoolean done = new AtomicBoolean(); 307 Thread t = newStartedThread(new CheckedRunnable() { 308 public void realRun() { 309 while (!done.get()) { 310 try { 311 while (c.isBroken()) 312 c.reset(); 313 314 c.await(); 315 shouldThrow(); 316 } 317 catch (BrokenBarrierException ok) {} 318 catch (InterruptedException ok) {} 319 }}}); 320 321 for (int i = 0; i < 4; i++) { 322 delay(timeoutMillis()); 323 t.interrupt(); 324 } 325 done.set(true); 326 t.interrupt(); 327 awaitTermination(t); 328 } 329 330 /** 331 * Reset of a non-broken barrier does not break barrier 332 */ 333 public void testResetWithoutBreakage() throws Exception { 334 final CyclicBarrier barrier = new CyclicBarrier(3); 335 for (int i = 0; i < 3; i++) { 336 final CyclicBarrier start = new CyclicBarrier(3); 337 Thread t1 = newStartedThread(new CheckedRunnable() { 338 public void realRun() throws Exception { 339 start.await(); 340 barrier.await(); 341 }}); 342 343 Thread t2 = newStartedThread(new CheckedRunnable() { 344 public void realRun() throws Exception { 345 start.await(); 346 barrier.await(); 347 }}); 348 349 start.await(); 350 barrier.await(); 351 awaitTermination(t1); 352 awaitTermination(t2); 353 assertFalse(barrier.isBroken()); 354 assertEquals(0, barrier.getNumberWaiting()); 355 if (i == 1) barrier.reset(); 356 assertFalse(barrier.isBroken()); 357 assertEquals(0, barrier.getNumberWaiting()); 358 } 359 } 360 361 /** 362 * Reset of a barrier after interruption reinitializes it. 363 */ 364 public void testResetAfterInterrupt() throws Exception { 365 final CyclicBarrier barrier = new CyclicBarrier(3); 366 for (int i = 0; i < 2; i++) { 367 final CyclicBarrier start = new CyclicBarrier(3); 368 Thread t1 = new ThreadShouldThrow(InterruptedException.class) { 369 public void realRun() throws Exception { 370 start.await(); 371 barrier.await(); 372 }}; 373 374 Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { 375 public void realRun() throws Exception { 376 start.await(); 377 barrier.await(); 378 }}; 379 380 t1.start(); 381 t2.start(); 382 start.await(); 383 t1.interrupt(); 384 awaitTermination(t1); 385 awaitTermination(t2); 386 assertTrue(barrier.isBroken()); 387 assertEquals(0, barrier.getNumberWaiting()); 388 barrier.reset(); 389 assertFalse(barrier.isBroken()); 390 assertEquals(0, barrier.getNumberWaiting()); 391 } 392 } 393 394 /** 395 * Reset of a barrier after timeout reinitializes it. 396 */ 397 public void testResetAfterTimeout() throws Exception { 398 final CyclicBarrier barrier = new CyclicBarrier(3); 399 for (int i = 0; i < 2; i++) { 400 assertEquals(0, barrier.getNumberWaiting()); 401 Thread t1 = newStartedThread(new CheckedRunnable() { 402 public void realRun() throws Exception { 403 try { 404 barrier.await(); 405 shouldThrow(); 406 } catch (BrokenBarrierException success) {} 407 }}); 408 Thread t2 = newStartedThread(new CheckedRunnable() { 409 public void realRun() throws Exception { 410 awaitNumberWaiting(barrier, 1); 411 long startTime = System.nanoTime(); 412 try { 413 barrier.await(timeoutMillis(), MILLISECONDS); 414 shouldThrow(); 415 } catch (TimeoutException success) {} 416 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 417 }}); 418 419 awaitTermination(t1); 420 awaitTermination(t2); 421 assertEquals(0, barrier.getNumberWaiting()); 422 assertTrue(barrier.isBroken()); 423 assertEquals(0, barrier.getNumberWaiting()); 424 barrier.reset(); 425 assertFalse(barrier.isBroken()); 426 assertEquals(0, barrier.getNumberWaiting()); 427 } 428 } 429 430 /** 431 * Reset of a barrier after a failed command reinitializes it. 432 */ 433 public void testResetAfterCommandException() throws Exception { 434 final CyclicBarrier barrier = 435 new CyclicBarrier(3, new Runnable() { 436 public void run() { 437 throw new NullPointerException(); }}); 438 for (int i = 0; i < 2; i++) { 439 final CyclicBarrier start = new CyclicBarrier(3); 440 Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { 441 public void realRun() throws Exception { 442 start.await(); 443 barrier.await(); 444 }}; 445 446 Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { 447 public void realRun() throws Exception { 448 start.await(); 449 barrier.await(); 450 }}; 451 452 t1.start(); 453 t2.start(); 454 start.await(); 455 awaitNumberWaiting(barrier, 2); 456 try { 457 barrier.await(); 458 shouldThrow(); 459 } catch (NullPointerException success) {} 460 awaitTermination(t1); 461 awaitTermination(t2); 462 assertTrue(barrier.isBroken()); 463 assertEquals(0, barrier.getNumberWaiting()); 464 barrier.reset(); 465 assertFalse(barrier.isBroken()); 466 assertEquals(0, barrier.getNumberWaiting()); 467 } 468 } 469 } 470