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