Home | History | Annotate | Download | only in jsr166
      1 /*
      2  * Written by Doug Lea and Martin Buchholz with assistance from
      3  * members of JCP JSR-166 Expert Group and released to the public
      4  * domain, as explained at
      5  * http://creativecommons.org/publicdomain/zero/1.0/
      6  * Other contributors include Andrew Wright, Jeffrey Hayes,
      7  * Pat Fisher, Mike Judd.
      8  */
      9 
     10 package jsr166;
     11 
     12 import junit.framework.*;
     13 import java.util.concurrent.CountDownLatch;
     14 import java.util.concurrent.atomic.AtomicBoolean;
     15 import java.util.concurrent.locks.LockSupport;
     16 import static java.util.concurrent.TimeUnit.MILLISECONDS;
     17 
     18 public class LockSupportTest extends JSR166TestCase {
     19 
     20     /**
     21      * Returns the blocker object used by tests in this file.
     22      * Any old object will do; we'll return a convenient one.
     23      */
     24     static Object theBlocker() {
     25         return LockSupportTest.class;
     26     }
     27 
     28     enum ParkMethod {
     29         park() {
     30             void park() {
     31                 LockSupport.park();
     32             }
     33             void park(long millis) {
     34                 throw new UnsupportedOperationException();
     35             }
     36         },
     37         parkUntil() {
     38             void park(long millis) {
     39                 LockSupport.parkUntil(deadline(millis));
     40             }
     41         },
     42         parkNanos() {
     43             void park(long millis) {
     44                 LockSupport.parkNanos(MILLISECONDS.toNanos(millis));
     45             }
     46         },
     47         parkBlocker() {
     48             void park() {
     49                 LockSupport.park(theBlocker());
     50             }
     51             void park(long millis) {
     52                 throw new UnsupportedOperationException();
     53             }
     54         },
     55         parkUntilBlocker() {
     56             void park(long millis) {
     57                 LockSupport.parkUntil(theBlocker(), deadline(millis));
     58             }
     59         },
     60         parkNanosBlocker() {
     61             void park(long millis) {
     62                 LockSupport.parkNanos(theBlocker(),
     63                                       MILLISECONDS.toNanos(millis));
     64             }
     65         };
     66 
     67         void park() { park(2 * LONG_DELAY_MS); }
     68         abstract void park(long millis);
     69 
     70         /** Returns a deadline to use with parkUntil. */
     71         long deadline(long millis) {
     72             // beware of rounding
     73             return System.currentTimeMillis() + millis + 1;
     74         }
     75     }
     76 
     77     /**
     78      * park is released by subsequent unpark
     79      */
     80     public void testParkBeforeUnpark_park() {
     81         testParkBeforeUnpark(ParkMethod.park);
     82     }
     83     public void testParkBeforeUnpark_parkNanos() {
     84         testParkBeforeUnpark(ParkMethod.parkNanos);
     85     }
     86     public void testParkBeforeUnpark_parkUntil() {
     87         testParkBeforeUnpark(ParkMethod.parkUntil);
     88     }
     89     public void testParkBeforeUnpark_parkBlocker() {
     90         testParkBeforeUnpark(ParkMethod.parkBlocker);
     91     }
     92     public void testParkBeforeUnpark_parkNanosBlocker() {
     93         testParkBeforeUnpark(ParkMethod.parkNanosBlocker);
     94     }
     95     public void testParkBeforeUnpark_parkUntilBlocker() {
     96         testParkBeforeUnpark(ParkMethod.parkUntilBlocker);
     97     }
     98     public void testParkBeforeUnpark(final ParkMethod parkMethod) {
     99         final CountDownLatch pleaseUnpark = new CountDownLatch(1);
    100         Thread t = newStartedThread(new CheckedRunnable() {
    101             public void realRun() {
    102                 pleaseUnpark.countDown();
    103                 parkMethod.park();
    104             }});
    105 
    106         await(pleaseUnpark);
    107         LockSupport.unpark(t);
    108         awaitTermination(t);
    109     }
    110 
    111     /**
    112      * park is released by preceding unpark
    113      */
    114     public void testParkAfterUnpark_park() {
    115         testParkAfterUnpark(ParkMethod.park);
    116     }
    117     public void testParkAfterUnpark_parkNanos() {
    118         testParkAfterUnpark(ParkMethod.parkNanos);
    119     }
    120     public void testParkAfterUnpark_parkUntil() {
    121         testParkAfterUnpark(ParkMethod.parkUntil);
    122     }
    123     public void testParkAfterUnpark_parkBlocker() {
    124         testParkAfterUnpark(ParkMethod.parkBlocker);
    125     }
    126     public void testParkAfterUnpark_parkNanosBlocker() {
    127         testParkAfterUnpark(ParkMethod.parkNanosBlocker);
    128     }
    129     public void testParkAfterUnpark_parkUntilBlocker() {
    130         testParkAfterUnpark(ParkMethod.parkUntilBlocker);
    131     }
    132     public void testParkAfterUnpark(final ParkMethod parkMethod) {
    133         final CountDownLatch pleaseUnpark = new CountDownLatch(1);
    134         final AtomicBoolean pleasePark = new AtomicBoolean(false);
    135         Thread t = newStartedThread(new CheckedRunnable() {
    136             public void realRun() {
    137                 pleaseUnpark.countDown();
    138                 while (!pleasePark.get())
    139                     Thread.yield();
    140                 parkMethod.park();
    141             }});
    142 
    143         await(pleaseUnpark);
    144         LockSupport.unpark(t);
    145         pleasePark.set(true);
    146         awaitTermination(t);
    147     }
    148 
    149     /**
    150      * park is released by subsequent interrupt
    151      */
    152     public void testParkBeforeInterrupt_park() {
    153         testParkBeforeInterrupt(ParkMethod.park);
    154     }
    155     public void testParkBeforeInterrupt_parkNanos() {
    156         testParkBeforeInterrupt(ParkMethod.parkNanos);
    157     }
    158     public void testParkBeforeInterrupt_parkUntil() {
    159         testParkBeforeInterrupt(ParkMethod.parkUntil);
    160     }
    161     public void testParkBeforeInterrupt_parkBlocker() {
    162         testParkBeforeInterrupt(ParkMethod.parkBlocker);
    163     }
    164     public void testParkBeforeInterrupt_parkNanosBlocker() {
    165         testParkBeforeInterrupt(ParkMethod.parkNanosBlocker);
    166     }
    167     public void testParkBeforeInterrupt_parkUntilBlocker() {
    168         testParkBeforeInterrupt(ParkMethod.parkUntilBlocker);
    169     }
    170     public void testParkBeforeInterrupt(final ParkMethod parkMethod) {
    171         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
    172         Thread t = newStartedThread(new CheckedRunnable() {
    173             public void realRun() {
    174                 pleaseInterrupt.countDown();
    175                 do {
    176                     parkMethod.park();
    177                     // park may return spuriously
    178                 } while (! Thread.currentThread().isInterrupted());
    179             }});
    180 
    181         await(pleaseInterrupt);
    182         assertThreadStaysAlive(t);
    183         t.interrupt();
    184         awaitTermination(t);
    185     }
    186 
    187     /**
    188      * park is released by preceding interrupt
    189      */
    190     public void testParkAfterInterrupt_park() {
    191         testParkAfterInterrupt(ParkMethod.park);
    192     }
    193     public void testParkAfterInterrupt_parkNanos() {
    194         testParkAfterInterrupt(ParkMethod.parkNanos);
    195     }
    196     public void testParkAfterInterrupt_parkUntil() {
    197         testParkAfterInterrupt(ParkMethod.parkUntil);
    198     }
    199     public void testParkAfterInterrupt_parkBlocker() {
    200         testParkAfterInterrupt(ParkMethod.parkBlocker);
    201     }
    202     public void testParkAfterInterrupt_parkNanosBlocker() {
    203         testParkAfterInterrupt(ParkMethod.parkNanosBlocker);
    204     }
    205     public void testParkAfterInterrupt_parkUntilBlocker() {
    206         testParkAfterInterrupt(ParkMethod.parkUntilBlocker);
    207     }
    208     public void testParkAfterInterrupt(final ParkMethod parkMethod) {
    209         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
    210         final AtomicBoolean pleasePark = new AtomicBoolean(false);
    211         Thread t = newStartedThread(new CheckedRunnable() {
    212             public void realRun() throws Exception {
    213                 pleaseInterrupt.countDown();
    214                 while (!pleasePark.get())
    215                     Thread.yield();
    216                 assertTrue(Thread.currentThread().isInterrupted());
    217                 parkMethod.park();
    218                 assertTrue(Thread.currentThread().isInterrupted());
    219             }});
    220 
    221         await(pleaseInterrupt);
    222         t.interrupt();
    223         pleasePark.set(true);
    224         awaitTermination(t);
    225     }
    226 
    227     /**
    228      * timed park times out if not unparked
    229      */
    230     public void testParkTimesOut_parkNanos() {
    231         testParkTimesOut(ParkMethod.parkNanos);
    232     }
    233     public void testParkTimesOut_parkUntil() {
    234         testParkTimesOut(ParkMethod.parkUntil);
    235     }
    236     public void testParkTimesOut_parkNanosBlocker() {
    237         testParkTimesOut(ParkMethod.parkNanosBlocker);
    238     }
    239     public void testParkTimesOut_parkUntilBlocker() {
    240         testParkTimesOut(ParkMethod.parkUntilBlocker);
    241     }
    242     public void testParkTimesOut(final ParkMethod parkMethod) {
    243         Thread t = newStartedThread(new CheckedRunnable() {
    244             public void realRun() {
    245                 for (;;) {
    246                     long startTime = System.nanoTime();
    247                     parkMethod.park(timeoutMillis());
    248                     // park may return spuriously
    249                     if (millisElapsedSince(startTime) >= timeoutMillis())
    250                         return;
    251                 }
    252             }});
    253 
    254         awaitTermination(t);
    255     }
    256 
    257     /**
    258      * getBlocker(null) throws NullPointerException
    259      */
    260     public void testGetBlockerNull() {
    261         try {
    262             LockSupport.getBlocker(null);
    263             shouldThrow();
    264         } catch (NullPointerException success) {}
    265     }
    266 
    267     /**
    268      * getBlocker returns the blocker object passed to park
    269      */
    270     public void testGetBlocker_parkBlocker() {
    271         testGetBlocker(ParkMethod.parkBlocker);
    272     }
    273     public void testGetBlocker_parkNanosBlocker() {
    274         testGetBlocker(ParkMethod.parkNanosBlocker);
    275     }
    276     public void testGetBlocker_parkUntilBlocker() {
    277         testGetBlocker(ParkMethod.parkUntilBlocker);
    278     }
    279     public void testGetBlocker(final ParkMethod parkMethod) {
    280         final CountDownLatch started = new CountDownLatch(1);
    281         Thread t = newStartedThread(new CheckedRunnable() {
    282             public void realRun() {
    283                 Thread t = Thread.currentThread();
    284                 started.countDown();
    285                 do {
    286                     assertNull(LockSupport.getBlocker(t));
    287                     parkMethod.park();
    288                     assertNull(LockSupport.getBlocker(t));
    289                     // park may return spuriously
    290                 } while (! Thread.currentThread().isInterrupted());
    291             }});
    292 
    293         long startTime = System.nanoTime();
    294         await(started);
    295         for (;;) {
    296             Object x = LockSupport.getBlocker(t);
    297             if (x == theBlocker()) { // success
    298                 t.interrupt();
    299                 awaitTermination(t);
    300                 assertNull(LockSupport.getBlocker(t));
    301                 return;
    302             } else {
    303                 assertNull(x);  // ok
    304                 if (millisElapsedSince(startTime) > LONG_DELAY_MS)
    305                     fail("timed out");
    306                 Thread.yield();
    307             }
    308         }
    309     }
    310 
    311     /**
    312      * timed park(0) returns immediately.
    313      *
    314      * Requires hotspot fix for:
    315      * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever
    316      * which is in jdk7-b118 and 6u25.
    317      */
    318     public void testPark0_parkNanos() {
    319         testPark0(ParkMethod.parkNanos);
    320     }
    321     public void testPark0_parkUntil() {
    322         testPark0(ParkMethod.parkUntil);
    323     }
    324     public void testPark0_parkNanosBlocker() {
    325         testPark0(ParkMethod.parkNanosBlocker);
    326     }
    327     public void testPark0_parkUntilBlocker() {
    328         testPark0(ParkMethod.parkUntilBlocker);
    329     }
    330     public void testPark0(final ParkMethod parkMethod) {
    331         Thread t = newStartedThread(new CheckedRunnable() {
    332             public void realRun() {
    333                 parkMethod.park(0L);
    334             }});
    335 
    336         awaitTermination(t);
    337     }
    338 
    339     /**
    340      * timed park(Long.MIN_VALUE) returns immediately.
    341      */
    342     public void testParkNeg_parkNanos() {
    343         testParkNeg(ParkMethod.parkNanos);
    344     }
    345     public void testParkNeg_parkUntil() {
    346         testParkNeg(ParkMethod.parkUntil);
    347     }
    348     public void testParkNeg_parkNanosBlocker() {
    349         testParkNeg(ParkMethod.parkNanosBlocker);
    350     }
    351     public void testParkNeg_parkUntilBlocker() {
    352         testParkNeg(ParkMethod.parkUntilBlocker);
    353     }
    354     public void testParkNeg(final ParkMethod parkMethod) {
    355         Thread t = newStartedThread(new CheckedRunnable() {
    356             public void realRun() {
    357                 parkMethod.park(Long.MIN_VALUE);
    358             }});
    359 
    360         awaitTermination(t);
    361     }
    362 }
    363