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 junit.framework.*;
     12 import java.util.*;
     13 import java.util.concurrent.CountDownLatch;
     14 import java.util.concurrent.Semaphore;
     15 import static java.util.concurrent.TimeUnit.MILLISECONDS;
     16 
     17 public class SemaphoreTest extends JSR166TestCase {
     18 
     19     /**
     20      * Subclass to expose protected methods
     21      */
     22     static class PublicSemaphore extends Semaphore {
     23         PublicSemaphore(int permits) { super(permits); }
     24         PublicSemaphore(int permits, boolean fair) { super(permits, fair); }
     25         public Collection<Thread> getQueuedThreads() {
     26             return super.getQueuedThreads();
     27         }
     28         public boolean hasQueuedThread(Thread t) {
     29             return super.getQueuedThreads().contains(t);
     30         }
     31         public void reducePermits(int reduction) {
     32             super.reducePermits(reduction);
     33         }
     34     }
     35 
     36     /**
     37      * A runnable calling acquire
     38      */
     39     class InterruptibleLockRunnable extends CheckedRunnable {
     40         final Semaphore lock;
     41         InterruptibleLockRunnable(Semaphore s) { lock = s; }
     42         public void realRun() {
     43             try {
     44                 lock.acquire();
     45             }
     46             catch (InterruptedException ignored) {}
     47         }
     48     }
     49 
     50     /**
     51      * A runnable calling acquire that expects to be interrupted
     52      */
     53     class InterruptedLockRunnable extends CheckedInterruptedRunnable {
     54         final Semaphore lock;
     55         InterruptedLockRunnable(Semaphore s) { lock = s; }
     56         public void realRun() throws InterruptedException {
     57             lock.acquire();
     58         }
     59     }
     60 
     61     /**
     62      * Spin-waits until s.hasQueuedThread(t) becomes true.
     63      */
     64     void waitForQueuedThread(PublicSemaphore s, Thread t) {
     65         long startTime = System.nanoTime();
     66         while (!s.hasQueuedThread(t)) {
     67             if (millisElapsedSince(startTime) > LONG_DELAY_MS)
     68                 throw new AssertionFailedError("timed out");
     69             Thread.yield();
     70         }
     71         assertTrue(s.hasQueuedThreads());
     72         assertTrue(t.isAlive());
     73     }
     74 
     75     /**
     76      * Spin-waits until s.hasQueuedThreads() becomes true.
     77      */
     78     void waitForQueuedThreads(Semaphore s) {
     79         long startTime = System.nanoTime();
     80         while (!s.hasQueuedThreads()) {
     81             if (millisElapsedSince(startTime) > LONG_DELAY_MS)
     82                 throw new AssertionFailedError("timed out");
     83             Thread.yield();
     84         }
     85     }
     86 
     87     enum AcquireMethod {
     88         acquire() {
     89             void acquire(Semaphore s) throws InterruptedException {
     90                 s.acquire();
     91             }
     92         },
     93         acquireN() {
     94             void acquire(Semaphore s, int permits) throws InterruptedException {
     95                 s.acquire(permits);
     96             }
     97         },
     98         acquireUninterruptibly() {
     99             void acquire(Semaphore s) {
    100                 s.acquireUninterruptibly();
    101             }
    102         },
    103         acquireUninterruptiblyN() {
    104             void acquire(Semaphore s, int permits) {
    105                 s.acquireUninterruptibly(permits);
    106             }
    107         },
    108         tryAcquire() {
    109             void acquire(Semaphore s) {
    110                 assertTrue(s.tryAcquire());
    111             }
    112         },
    113         tryAcquireN() {
    114             void acquire(Semaphore s, int permits) {
    115                 assertTrue(s.tryAcquire(permits));
    116             }
    117         },
    118         tryAcquireTimed() {
    119             void acquire(Semaphore s) throws InterruptedException {
    120                 assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS));
    121             }
    122         },
    123         tryAcquireTimedN {
    124             void acquire(Semaphore s, int permits) throws InterruptedException {
    125                 assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS));
    126             }
    127         };
    128 
    129         // Intentionally meta-circular
    130 
    131         /** Acquires 1 permit. */
    132         void acquire(Semaphore s) throws InterruptedException {
    133             acquire(s, 1);
    134         }
    135         /** Acquires the given number of permits. */
    136         void acquire(Semaphore s, int permits) throws InterruptedException {
    137             for (int i = 0; i < permits; i++)
    138                 acquire(s);
    139         }
    140     }
    141 
    142     /**
    143      * Zero, negative, and positive initial values are allowed in constructor
    144      */
    145     public void testConstructor()      { testConstructor(false); }
    146     public void testConstructor_fair() { testConstructor(true); }
    147     public void testConstructor(boolean fair) {
    148         for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
    149             Semaphore s = new Semaphore(permits, fair);
    150             assertEquals(permits, s.availablePermits());
    151             assertEquals(fair, s.isFair());
    152         }
    153     }
    154 
    155     /**
    156      * Constructor without fairness argument behaves as nonfair
    157      */
    158     public void testConstructorDefaultsToNonFair() {
    159         for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
    160             Semaphore s = new Semaphore(permits);
    161             assertEquals(permits, s.availablePermits());
    162             assertFalse(s.isFair());
    163         }
    164     }
    165 
    166     /**
    167      * tryAcquire succeeds when sufficient permits, else fails
    168      */
    169     public void testTryAcquireInSameThread()      { testTryAcquireInSameThread(false); }
    170     public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); }
    171     public void testTryAcquireInSameThread(boolean fair) {
    172         Semaphore s = new Semaphore(2, fair);
    173         assertEquals(2, s.availablePermits());
    174         assertTrue(s.tryAcquire());
    175         assertTrue(s.tryAcquire());
    176         assertEquals(0, s.availablePermits());
    177         assertFalse(s.tryAcquire());
    178         assertFalse(s.tryAcquire());
    179         assertEquals(0, s.availablePermits());
    180     }
    181 
    182     /**
    183      * timed tryAcquire times out
    184      */
    185     public void testTryAcquire_timeout()      { testTryAcquire_timeout(false); }
    186     public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); }
    187     public void testTryAcquire_timeout(boolean fair) {
    188         Semaphore s = new Semaphore(0, fair);
    189         long startTime = System.nanoTime();
    190         try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); }
    191         catch (InterruptedException e) { threadUnexpectedException(e); }
    192         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
    193     }
    194 
    195     /**
    196      * timed tryAcquire(N) times out
    197      */
    198     public void testTryAcquireN_timeout()      { testTryAcquireN_timeout(false); }
    199     public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); }
    200     public void testTryAcquireN_timeout(boolean fair) {
    201         Semaphore s = new Semaphore(2, fair);
    202         long startTime = System.nanoTime();
    203         try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); }
    204         catch (InterruptedException e) { threadUnexpectedException(e); }
    205         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
    206     }
    207 
    208     /**
    209      * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N)
    210      * are interruptible
    211      */
    212     public void testInterruptible_acquire()               { testInterruptible(false, AcquireMethod.acquire); }
    213     public void testInterruptible_acquire_fair()          { testInterruptible(true,  AcquireMethod.acquire); }
    214     public void testInterruptible_acquireN()              { testInterruptible(false, AcquireMethod.acquireN); }
    215     public void testInterruptible_acquireN_fair()         { testInterruptible(true,  AcquireMethod.acquireN); }
    216     public void testInterruptible_tryAcquireTimed()       { testInterruptible(false, AcquireMethod.tryAcquireTimed); }
    217     public void testInterruptible_tryAcquireTimed_fair()  { testInterruptible(true,  AcquireMethod.tryAcquireTimed); }
    218     public void testInterruptible_tryAcquireTimedN()      { testInterruptible(false, AcquireMethod.tryAcquireTimedN); }
    219     public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true,  AcquireMethod.tryAcquireTimedN); }
    220     public void testInterruptible(boolean fair, final AcquireMethod acquirer) {
    221         final PublicSemaphore s = new PublicSemaphore(0, fair);
    222         final Semaphore pleaseInterrupt = new Semaphore(0, fair);
    223         Thread t = newStartedThread(new CheckedRunnable() {
    224             public void realRun() {
    225                 // Interrupt before acquire
    226                 Thread.currentThread().interrupt();
    227                 try {
    228                     acquirer.acquire(s);
    229                     shouldThrow();
    230                 } catch (InterruptedException success) {}
    231 
    232                 // Interrupt during acquire
    233                 try {
    234                     acquirer.acquire(s);
    235                     shouldThrow();
    236                 } catch (InterruptedException success) {}
    237 
    238                 // Interrupt before acquire(N)
    239                 Thread.currentThread().interrupt();
    240                 try {
    241                     acquirer.acquire(s, 3);
    242                     shouldThrow();
    243                 } catch (InterruptedException success) {}
    244 
    245                 pleaseInterrupt.release();
    246 
    247                 // Interrupt during acquire(N)
    248                 try {
    249                     acquirer.acquire(s, 3);
    250                     shouldThrow();
    251                 } catch (InterruptedException success) {}
    252             }});
    253 
    254         waitForQueuedThread(s, t);
    255         t.interrupt();
    256         await(pleaseInterrupt);
    257         waitForQueuedThread(s, t);
    258         t.interrupt();
    259         awaitTermination(t);
    260     }
    261 
    262     /**
    263      * acquireUninterruptibly(), acquireUninterruptibly(N) are
    264      * uninterruptible
    265      */
    266     public void testUninterruptible_acquireUninterruptibly()       { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); }
    267     public void testUninterruptible_acquireUninterruptibly_fair()  { testUninterruptible(true,  AcquireMethod.acquireUninterruptibly); }
    268     public void testUninterruptible_acquireUninterruptiblyN()      { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); }
    269     public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true,  AcquireMethod.acquireUninterruptiblyN); }
    270     public void testUninterruptible(boolean fair, final AcquireMethod acquirer) {
    271         final PublicSemaphore s = new PublicSemaphore(0, fair);
    272         final Semaphore pleaseInterrupt = new Semaphore(-1, fair);
    273 
    274         Thread t1 = newStartedThread(new CheckedRunnable() {
    275             public void realRun() throws InterruptedException {
    276                 // Interrupt before acquire
    277                 pleaseInterrupt.release();
    278                 Thread.currentThread().interrupt();
    279                 acquirer.acquire(s);
    280                 assertTrue(Thread.interrupted());
    281             }});
    282 
    283         Thread t2 = newStartedThread(new CheckedRunnable() {
    284             public void realRun() throws InterruptedException {
    285                 // Interrupt during acquire
    286                 pleaseInterrupt.release();
    287                 acquirer.acquire(s);
    288                 assertTrue(Thread.interrupted());
    289             }});
    290 
    291         await(pleaseInterrupt);
    292         waitForQueuedThread(s, t1);
    293         waitForQueuedThread(s, t2);
    294         t2.interrupt();
    295 
    296         assertThreadStaysAlive(t1);
    297         assertTrue(t2.isAlive());
    298 
    299         s.release(2);
    300 
    301         awaitTermination(t1);
    302         awaitTermination(t2);
    303     }
    304 
    305     /**
    306      * hasQueuedThreads reports whether there are waiting threads
    307      */
    308     public void testHasQueuedThreads()      { testHasQueuedThreads(false); }
    309     public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); }
    310     public void testHasQueuedThreads(boolean fair) {
    311         final PublicSemaphore lock = new PublicSemaphore(1, fair);
    312         assertFalse(lock.hasQueuedThreads());
    313         lock.acquireUninterruptibly();
    314         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
    315         waitForQueuedThread(lock, t1);
    316         assertTrue(lock.hasQueuedThreads());
    317         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
    318         waitForQueuedThread(lock, t2);
    319         assertTrue(lock.hasQueuedThreads());
    320         t1.interrupt();
    321         awaitTermination(t1);
    322         assertTrue(lock.hasQueuedThreads());
    323         lock.release();
    324         awaitTermination(t2);
    325         assertFalse(lock.hasQueuedThreads());
    326     }
    327 
    328     /**
    329      * getQueueLength reports number of waiting threads
    330      */
    331     public void testGetQueueLength()      { testGetQueueLength(false); }
    332     public void testGetQueueLength_fair() { testGetQueueLength(true); }
    333     public void testGetQueueLength(boolean fair) {
    334         final PublicSemaphore lock = new PublicSemaphore(1, fair);
    335         assertEquals(0, lock.getQueueLength());
    336         lock.acquireUninterruptibly();
    337         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
    338         waitForQueuedThread(lock, t1);
    339         assertEquals(1, lock.getQueueLength());
    340         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
    341         waitForQueuedThread(lock, t2);
    342         assertEquals(2, lock.getQueueLength());
    343         t1.interrupt();
    344         awaitTermination(t1);
    345         assertEquals(1, lock.getQueueLength());
    346         lock.release();
    347         awaitTermination(t2);
    348         assertEquals(0, lock.getQueueLength());
    349     }
    350 
    351     /**
    352      * getQueuedThreads includes waiting threads
    353      */
    354     public void testGetQueuedThreads()      { testGetQueuedThreads(false); }
    355     public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); }
    356     public void testGetQueuedThreads(boolean fair) {
    357         final PublicSemaphore lock = new PublicSemaphore(1, fair);
    358         assertTrue(lock.getQueuedThreads().isEmpty());
    359         lock.acquireUninterruptibly();
    360         assertTrue(lock.getQueuedThreads().isEmpty());
    361         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
    362         waitForQueuedThread(lock, t1);
    363         assertTrue(lock.getQueuedThreads().contains(t1));
    364         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
    365         waitForQueuedThread(lock, t2);
    366         assertTrue(lock.getQueuedThreads().contains(t1));
    367         assertTrue(lock.getQueuedThreads().contains(t2));
    368         t1.interrupt();
    369         awaitTermination(t1);
    370         assertFalse(lock.getQueuedThreads().contains(t1));
    371         assertTrue(lock.getQueuedThreads().contains(t2));
    372         lock.release();
    373         awaitTermination(t2);
    374         assertTrue(lock.getQueuedThreads().isEmpty());
    375     }
    376 
    377     /**
    378      * drainPermits reports and removes given number of permits
    379      */
    380     public void testDrainPermits()      { testDrainPermits(false); }
    381     public void testDrainPermits_fair() { testDrainPermits(true); }
    382     public void testDrainPermits(boolean fair) {
    383         Semaphore s = new Semaphore(0, fair);
    384         assertEquals(0, s.availablePermits());
    385         assertEquals(0, s.drainPermits());
    386         s.release(10);
    387         assertEquals(10, s.availablePermits());
    388         assertEquals(10, s.drainPermits());
    389         assertEquals(0, s.availablePermits());
    390         assertEquals(0, s.drainPermits());
    391     }
    392 
    393     /**
    394      * release(-N) throws IllegalArgumentException
    395      */
    396     public void testReleaseIAE()      { testReleaseIAE(false); }
    397     public void testReleaseIAE_fair() { testReleaseIAE(true); }
    398     public void testReleaseIAE(boolean fair) {
    399         Semaphore s = new Semaphore(10, fair);
    400         try {
    401             s.release(-1);
    402             shouldThrow();
    403         } catch (IllegalArgumentException success) {}
    404     }
    405 
    406     /**
    407      * reducePermits(-N) throws IllegalArgumentException
    408      */
    409     public void testReducePermitsIAE()      { testReducePermitsIAE(false); }
    410     public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); }
    411     public void testReducePermitsIAE(boolean fair) {
    412         PublicSemaphore s = new PublicSemaphore(10, fair);
    413         try {
    414             s.reducePermits(-1);
    415             shouldThrow();
    416         } catch (IllegalArgumentException success) {}
    417     }
    418 
    419     /**
    420      * reducePermits reduces number of permits
    421      */
    422     public void testReducePermits()      { testReducePermits(false); }
    423     public void testReducePermits_fair() { testReducePermits(true); }
    424     public void testReducePermits(boolean fair) {
    425         PublicSemaphore s = new PublicSemaphore(10, fair);
    426         assertEquals(10, s.availablePermits());
    427         s.reducePermits(0);
    428         assertEquals(10, s.availablePermits());
    429         s.reducePermits(1);
    430         assertEquals(9, s.availablePermits());
    431         s.reducePermits(10);
    432         assertEquals(-1, s.availablePermits());
    433         s.reducePermits(10);
    434         assertEquals(-11, s.availablePermits());
    435         s.reducePermits(0);
    436         assertEquals(-11, s.availablePermits());
    437     }
    438 
    439     /**
    440      * a reserialized semaphore has same number of permits and
    441      * fairness, but no queued threads
    442      */
    443     public void testSerialization()      { testSerialization(false); }
    444     public void testSerialization_fair() { testSerialization(true); }
    445     public void testSerialization(boolean fair) {
    446         try {
    447             Semaphore s = new Semaphore(3, fair);
    448             s.acquire();
    449             s.acquire();
    450             s.release();
    451 
    452             Semaphore clone = serialClone(s);
    453             assertEquals(fair, s.isFair());
    454             assertEquals(fair, clone.isFair());
    455             assertEquals(2, s.availablePermits());
    456             assertEquals(2, clone.availablePermits());
    457             clone.acquire();
    458             clone.acquire();
    459             clone.release();
    460             assertEquals(2, s.availablePermits());
    461             assertEquals(1, clone.availablePermits());
    462 
    463             s = new Semaphore(0, fair);
    464             Thread t = newStartedThread(new InterruptibleLockRunnable(s));
    465             waitForQueuedThreads(s);
    466             clone = serialClone(s);
    467             assertEquals(fair, s.isFair());
    468             assertEquals(fair, clone.isFair());
    469             assertEquals(0, s.availablePermits());
    470             assertEquals(0, clone.availablePermits());
    471             assertTrue(s.hasQueuedThreads());
    472             assertFalse(clone.hasQueuedThreads());
    473             s.release();
    474             awaitTermination(t);
    475             assertFalse(s.hasQueuedThreads());
    476             assertFalse(clone.hasQueuedThreads());
    477         } catch (InterruptedException e) { threadUnexpectedException(e); }
    478     }
    479 
    480     /**
    481      * tryAcquire(n) succeeds when sufficient permits, else fails
    482      */
    483     public void testTryAcquireNInSameThread()      { testTryAcquireNInSameThread(false); }
    484     public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); }
    485     public void testTryAcquireNInSameThread(boolean fair) {
    486         Semaphore s = new Semaphore(2, fair);
    487         assertEquals(2, s.availablePermits());
    488         assertFalse(s.tryAcquire(3));
    489         assertEquals(2, s.availablePermits());
    490         assertTrue(s.tryAcquire(2));
    491         assertEquals(0, s.availablePermits());
    492         assertFalse(s.tryAcquire(1));
    493         assertFalse(s.tryAcquire(2));
    494         assertEquals(0, s.availablePermits());
    495     }
    496 
    497     /**
    498      * acquire succeeds if permits available
    499      */
    500     public void testReleaseAcquireSameThread_acquire()       { testReleaseAcquireSameThread(false, AcquireMethod.acquire); }
    501     public void testReleaseAcquireSameThread_acquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquire); }
    502     public void testReleaseAcquireSameThread_acquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); }
    503     public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); }
    504     public void testReleaseAcquireSameThread_acquireUninterruptibly()       { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
    505     public void testReleaseAcquireSameThread_acquireUninterruptibly_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
    506     public void testReleaseAcquireSameThread_acquireUninterruptiblyN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
    507     public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
    508     public void testReleaseAcquireSameThread_tryAcquire()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); }
    509     public void testReleaseAcquireSameThread_tryAcquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); }
    510     public void testReleaseAcquireSameThread_tryAcquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); }
    511     public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); }
    512     public void testReleaseAcquireSameThread_tryAcquireTimed()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); }
    513     public void testReleaseAcquireSameThread_tryAcquireTimed_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); }
    514     public void testReleaseAcquireSameThread_tryAcquireTimedN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); }
    515     public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); }
    516     public void testReleaseAcquireSameThread(boolean fair,
    517                                              final AcquireMethod acquirer) {
    518         Semaphore s = new Semaphore(1, fair);
    519         for (int i = 1; i < 6; i++) {
    520             s.release(i);
    521             assertEquals(1 + i, s.availablePermits());
    522             try {
    523                 acquirer.acquire(s, i);
    524             } catch (InterruptedException e) { threadUnexpectedException(e); }
    525             assertEquals(1, s.availablePermits());
    526         }
    527     }
    528 
    529     /**
    530      * release in one thread enables acquire in another thread
    531      */
    532     public void testReleaseAcquireDifferentThreads_acquire()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); }
    533     public void testReleaseAcquireDifferentThreads_acquire_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); }
    534     public void testReleaseAcquireDifferentThreads_acquireN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); }
    535     public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); }
    536     public void testReleaseAcquireDifferentThreads_acquireUninterruptibly()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
    537     public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
    538     public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
    539     public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
    540     public void testReleaseAcquireDifferentThreads_tryAcquireTimed()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); }
    541     public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); }
    542     public void testReleaseAcquireDifferentThreads_tryAcquireTimedN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); }
    543     public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); }
    544     public void testReleaseAcquireDifferentThreads(boolean fair,
    545                                                    final AcquireMethod acquirer) {
    546         final Semaphore s = new Semaphore(0, fair);
    547         final int rounds = 4;
    548         long startTime = System.nanoTime();
    549         Thread t = newStartedThread(new CheckedRunnable() {
    550             public void realRun() throws InterruptedException {
    551                 for (int i = 0; i < rounds; i++) {
    552                     assertFalse(s.hasQueuedThreads());
    553                     if (i % 2 == 0)
    554                         acquirer.acquire(s);
    555                     else
    556                         acquirer.acquire(s, 3);
    557                 }}});
    558 
    559         for (int i = 0; i < rounds; i++) {
    560             while (! (s.availablePermits() == 0 && s.hasQueuedThreads()))
    561                 Thread.yield();
    562             assertTrue(t.isAlive());
    563             if (i % 2 == 0)
    564                 s.release();
    565             else
    566                 s.release(3);
    567         }
    568         awaitTermination(t);
    569         assertEquals(0, s.availablePermits());
    570         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
    571     }
    572 
    573     /**
    574      * fair locks are strictly FIFO
    575      */
    576     public void testFairLocksFifo() {
    577         final PublicSemaphore s = new PublicSemaphore(1, true);
    578         final CountDownLatch pleaseRelease = new CountDownLatch(1);
    579         Thread t1 = newStartedThread(new CheckedRunnable() {
    580             public void realRun() throws InterruptedException {
    581                 // Will block; permits are available, but not three
    582                 s.acquire(3);
    583             }});
    584 
    585         waitForQueuedThreads(s);
    586 
    587         Thread t2 = newStartedThread(new CheckedRunnable() {
    588             public void realRun() throws InterruptedException {
    589                 // Will fail, even though 1 permit is available
    590                 assertFalse(s.tryAcquire(0L, MILLISECONDS));
    591                 assertFalse(s.tryAcquire(1, 0L, MILLISECONDS));
    592 
    593                 // untimed tryAcquire will barge and succeed
    594                 assertTrue(s.tryAcquire());
    595                 s.release(2);
    596                 assertTrue(s.tryAcquire(2));
    597                 s.release();
    598 
    599                 pleaseRelease.countDown();
    600                 // Will queue up behind t1, even though 1 permit is available
    601                 s.acquire();
    602             }});
    603 
    604         await(pleaseRelease);
    605         waitForQueuedThread(s, t2);
    606         s.release(2);
    607         awaitTermination(t1);
    608         assertTrue(t2.isAlive());
    609         s.release();
    610         awaitTermination(t2);
    611    }
    612 
    613     /**
    614      * toString indicates current number of permits
    615      */
    616     public void testToString()      { testToString(false); }
    617     public void testToString_fair() { testToString(true); }
    618     public void testToString(boolean fair) {
    619         PublicSemaphore s = new PublicSemaphore(0, fair);
    620         assertTrue(s.toString().contains("Permits = 0"));
    621         s.release();
    622         assertTrue(s.toString().contains("Permits = 1"));
    623         s.release(2);
    624         assertTrue(s.toString().contains("Permits = 3"));
    625         s.reducePermits(5);
    626         assertTrue(s.toString().contains("Permits = -2"));
    627     }
    628 
    629 }
    630