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 {
run()35         public void run() { ++countAction; }
36     }
37 
38     /**
39      * Spin-waits till the number of waiters == numberOfWaiters.
40      */
awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters)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      */
testConstructor1()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      */
testConstructor2()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      */
testGetParties()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      */
testSingleParty()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      */
testBarrierAction()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      */
testTwoParties()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      */
testAwait1_Interrupted_BrokenBarrier()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      */
testAwait2_Interrupted_BrokenBarrier()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      */
testAwait3_TimeoutException()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      */
testAwait4_Timeout_BrokenBarrier()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      */
testAwait5_Timeout_BrokenBarrier()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      */
testReset_BrokenBarrier()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      */
testReset_NoBrokenBarrier()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      */
testReset_Leakage()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      */
testResetWithoutBreakage()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      */
testResetAfterInterrupt()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      */
testResetAfterTimeout()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      */
testResetAfterCommandException()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