Home | History | Annotate | Download | only in jsr166
      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