|  | /* | 
|  | * Written by Doug Lea with assistance from members of JCP JSR-166 | 
|  | * Expert Group and released to the public domain, as explained at | 
|  | * http://creativecommons.org/publicdomain/zero/1.0/ | 
|  | * Other contributors include Andrew Wright, Jeffrey Hayes, | 
|  | * Pat Fisher, Mike Judd. | 
|  | */ | 
|  |  | 
|  | package jsr166; | 
|  |  | 
|  | import static java.util.concurrent.TimeUnit.MILLISECONDS; | 
|  |  | 
|  | import java.util.Collection; | 
|  | import java.util.concurrent.CountDownLatch; | 
|  | import java.util.concurrent.Semaphore; | 
|  |  | 
|  | import junit.framework.AssertionFailedError; | 
|  | import junit.framework.Test; | 
|  | import junit.framework.TestSuite; | 
|  |  | 
|  | public class SemaphoreTest extends JSR166TestCase { | 
|  | // android-note: Removed because the CTS runner does a bad job of | 
|  | // retrying tests that have suite() declarations. | 
|  | // | 
|  | // public static void main(String[] args) { | 
|  | //     main(suite(), args); | 
|  | // } | 
|  | // public static Test suite() { | 
|  | //     return new TestSuite(SemaphoreTest.class); | 
|  | // } | 
|  |  | 
|  | /** | 
|  | * Subclass to expose protected methods | 
|  | */ | 
|  | static class PublicSemaphore extends Semaphore { | 
|  | PublicSemaphore(int permits) { super(permits); } | 
|  | PublicSemaphore(int permits, boolean fair) { super(permits, fair); } | 
|  | public Collection<Thread> getQueuedThreads() { | 
|  | return super.getQueuedThreads(); | 
|  | } | 
|  | public boolean hasQueuedThread(Thread t) { | 
|  | return super.getQueuedThreads().contains(t); | 
|  | } | 
|  | public void reducePermits(int reduction) { | 
|  | super.reducePermits(reduction); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A runnable calling acquire | 
|  | */ | 
|  | class InterruptibleLockRunnable extends CheckedRunnable { | 
|  | final Semaphore lock; | 
|  | InterruptibleLockRunnable(Semaphore s) { lock = s; } | 
|  | public void realRun() { | 
|  | try { | 
|  | lock.acquire(); | 
|  | } | 
|  | catch (InterruptedException ignored) {} | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A runnable calling acquire that expects to be interrupted | 
|  | */ | 
|  | class InterruptedLockRunnable extends CheckedInterruptedRunnable { | 
|  | final Semaphore lock; | 
|  | InterruptedLockRunnable(Semaphore s) { lock = s; } | 
|  | public void realRun() throws InterruptedException { | 
|  | lock.acquire(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Spin-waits until s.hasQueuedThread(t) becomes true. | 
|  | */ | 
|  | void waitForQueuedThread(PublicSemaphore s, Thread t) { | 
|  | long startTime = System.nanoTime(); | 
|  | while (!s.hasQueuedThread(t)) { | 
|  | if (millisElapsedSince(startTime) > LONG_DELAY_MS) | 
|  | throw new AssertionFailedError("timed out"); | 
|  | Thread.yield(); | 
|  | } | 
|  | assertTrue(s.hasQueuedThreads()); | 
|  | assertTrue(t.isAlive()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Spin-waits until s.hasQueuedThreads() becomes true. | 
|  | */ | 
|  | void waitForQueuedThreads(Semaphore s) { | 
|  | long startTime = System.nanoTime(); | 
|  | while (!s.hasQueuedThreads()) { | 
|  | if (millisElapsedSince(startTime) > LONG_DELAY_MS) | 
|  | throw new AssertionFailedError("timed out"); | 
|  | Thread.yield(); | 
|  | } | 
|  | } | 
|  |  | 
|  | enum AcquireMethod { | 
|  | acquire() { | 
|  | void acquire(Semaphore s) throws InterruptedException { | 
|  | s.acquire(); | 
|  | } | 
|  | }, | 
|  | acquireN() { | 
|  | void acquire(Semaphore s, int permits) throws InterruptedException { | 
|  | s.acquire(permits); | 
|  | } | 
|  | }, | 
|  | acquireUninterruptibly() { | 
|  | void acquire(Semaphore s) { | 
|  | s.acquireUninterruptibly(); | 
|  | } | 
|  | }, | 
|  | acquireUninterruptiblyN() { | 
|  | void acquire(Semaphore s, int permits) { | 
|  | s.acquireUninterruptibly(permits); | 
|  | } | 
|  | }, | 
|  | tryAcquire() { | 
|  | void acquire(Semaphore s) { | 
|  | assertTrue(s.tryAcquire()); | 
|  | } | 
|  | }, | 
|  | tryAcquireN() { | 
|  | void acquire(Semaphore s, int permits) { | 
|  | assertTrue(s.tryAcquire(permits)); | 
|  | } | 
|  | }, | 
|  | tryAcquireTimed() { | 
|  | void acquire(Semaphore s) throws InterruptedException { | 
|  | assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS)); | 
|  | } | 
|  | }, | 
|  | tryAcquireTimedN { | 
|  | void acquire(Semaphore s, int permits) throws InterruptedException { | 
|  | assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Intentionally meta-circular | 
|  |  | 
|  | /** Acquires 1 permit. */ | 
|  | void acquire(Semaphore s) throws InterruptedException { | 
|  | acquire(s, 1); | 
|  | } | 
|  | /** Acquires the given number of permits. */ | 
|  | void acquire(Semaphore s, int permits) throws InterruptedException { | 
|  | for (int i = 0; i < permits; i++) | 
|  | acquire(s); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Zero, negative, and positive initial values are allowed in constructor | 
|  | */ | 
|  | public void testConstructor()      { testConstructor(false); } | 
|  | public void testConstructor_fair() { testConstructor(true); } | 
|  | public void testConstructor(boolean fair) { | 
|  | for (int permits : new int[] { -42, -1, 0, 1, 42 }) { | 
|  | Semaphore s = new Semaphore(permits, fair); | 
|  | assertEquals(permits, s.availablePermits()); | 
|  | assertEquals(fair, s.isFair()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Constructor without fairness argument behaves as nonfair | 
|  | */ | 
|  | public void testConstructorDefaultsToNonFair() { | 
|  | for (int permits : new int[] { -42, -1, 0, 1, 42 }) { | 
|  | Semaphore s = new Semaphore(permits); | 
|  | assertEquals(permits, s.availablePermits()); | 
|  | assertFalse(s.isFair()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * tryAcquire succeeds when sufficient permits, else fails | 
|  | */ | 
|  | public void testTryAcquireInSameThread()      { testTryAcquireInSameThread(false); } | 
|  | public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); } | 
|  | public void testTryAcquireInSameThread(boolean fair) { | 
|  | Semaphore s = new Semaphore(2, fair); | 
|  | assertEquals(2, s.availablePermits()); | 
|  | assertTrue(s.tryAcquire()); | 
|  | assertTrue(s.tryAcquire()); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertFalse(s.tryAcquire()); | 
|  | assertFalse(s.tryAcquire()); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * timed tryAcquire times out | 
|  | */ | 
|  | public void testTryAcquire_timeout()      { testTryAcquire_timeout(false); } | 
|  | public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); } | 
|  | public void testTryAcquire_timeout(boolean fair) { | 
|  | Semaphore s = new Semaphore(0, fair); | 
|  | long startTime = System.nanoTime(); | 
|  | try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); } | 
|  | catch (InterruptedException e) { threadUnexpectedException(e); } | 
|  | assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * timed tryAcquire(N) times out | 
|  | */ | 
|  | public void testTryAcquireN_timeout()      { testTryAcquireN_timeout(false); } | 
|  | public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); } | 
|  | public void testTryAcquireN_timeout(boolean fair) { | 
|  | Semaphore s = new Semaphore(2, fair); | 
|  | long startTime = System.nanoTime(); | 
|  | try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); } | 
|  | catch (InterruptedException e) { threadUnexpectedException(e); } | 
|  | assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N) | 
|  | * are interruptible | 
|  | */ | 
|  | public void testInterruptible_acquire()               { testInterruptible(false, AcquireMethod.acquire); } | 
|  | public void testInterruptible_acquire_fair()          { testInterruptible(true,  AcquireMethod.acquire); } | 
|  | public void testInterruptible_acquireN()              { testInterruptible(false, AcquireMethod.acquireN); } | 
|  | public void testInterruptible_acquireN_fair()         { testInterruptible(true,  AcquireMethod.acquireN); } | 
|  | public void testInterruptible_tryAcquireTimed()       { testInterruptible(false, AcquireMethod.tryAcquireTimed); } | 
|  | public void testInterruptible_tryAcquireTimed_fair()  { testInterruptible(true,  AcquireMethod.tryAcquireTimed); } | 
|  | public void testInterruptible_tryAcquireTimedN()      { testInterruptible(false, AcquireMethod.tryAcquireTimedN); } | 
|  | public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true,  AcquireMethod.tryAcquireTimedN); } | 
|  | public void testInterruptible(boolean fair, final AcquireMethod acquirer) { | 
|  | final PublicSemaphore s = new PublicSemaphore(0, fair); | 
|  | final Semaphore pleaseInterrupt = new Semaphore(0, fair); | 
|  | Thread t = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() { | 
|  | // Interrupt before acquire | 
|  | Thread.currentThread().interrupt(); | 
|  | try { | 
|  | acquirer.acquire(s); | 
|  | shouldThrow(); | 
|  | } catch (InterruptedException success) {} | 
|  |  | 
|  | // Interrupt during acquire | 
|  | try { | 
|  | acquirer.acquire(s); | 
|  | shouldThrow(); | 
|  | } catch (InterruptedException success) {} | 
|  |  | 
|  | // Interrupt before acquire(N) | 
|  | Thread.currentThread().interrupt(); | 
|  | try { | 
|  | acquirer.acquire(s, 3); | 
|  | shouldThrow(); | 
|  | } catch (InterruptedException success) {} | 
|  |  | 
|  | pleaseInterrupt.release(); | 
|  |  | 
|  | // Interrupt during acquire(N) | 
|  | try { | 
|  | acquirer.acquire(s, 3); | 
|  | shouldThrow(); | 
|  | } catch (InterruptedException success) {} | 
|  | }}); | 
|  |  | 
|  | waitForQueuedThread(s, t); | 
|  | t.interrupt(); | 
|  | await(pleaseInterrupt); | 
|  | waitForQueuedThread(s, t); | 
|  | t.interrupt(); | 
|  | awaitTermination(t); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * acquireUninterruptibly(), acquireUninterruptibly(N) are | 
|  | * uninterruptible | 
|  | */ | 
|  | public void testUninterruptible_acquireUninterruptibly()       { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testUninterruptible_acquireUninterruptibly_fair()  { testUninterruptible(true,  AcquireMethod.acquireUninterruptibly); } | 
|  | public void testUninterruptible_acquireUninterruptiblyN()      { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); } | 
|  | public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true,  AcquireMethod.acquireUninterruptiblyN); } | 
|  | public void testUninterruptible(boolean fair, final AcquireMethod acquirer) { | 
|  | final PublicSemaphore s = new PublicSemaphore(0, fair); | 
|  | final Semaphore pleaseInterrupt = new Semaphore(-1, fair); | 
|  |  | 
|  | Thread t1 = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() throws InterruptedException { | 
|  | // Interrupt before acquire | 
|  | pleaseInterrupt.release(); | 
|  | Thread.currentThread().interrupt(); | 
|  | acquirer.acquire(s); | 
|  | assertTrue(Thread.interrupted()); | 
|  | }}); | 
|  |  | 
|  | Thread t2 = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() throws InterruptedException { | 
|  | // Interrupt during acquire | 
|  | pleaseInterrupt.release(); | 
|  | acquirer.acquire(s); | 
|  | assertTrue(Thread.interrupted()); | 
|  | }}); | 
|  |  | 
|  | await(pleaseInterrupt); | 
|  | waitForQueuedThread(s, t1); | 
|  | waitForQueuedThread(s, t2); | 
|  | t2.interrupt(); | 
|  |  | 
|  | assertThreadStaysAlive(t1); | 
|  | assertTrue(t2.isAlive()); | 
|  |  | 
|  | s.release(2); | 
|  |  | 
|  | awaitTermination(t1); | 
|  | awaitTermination(t2); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * hasQueuedThreads reports whether there are waiting threads | 
|  | */ | 
|  | public void testHasQueuedThreads()      { testHasQueuedThreads(false); } | 
|  | public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); } | 
|  | public void testHasQueuedThreads(boolean fair) { | 
|  | final PublicSemaphore lock = new PublicSemaphore(1, fair); | 
|  | assertFalse(lock.hasQueuedThreads()); | 
|  | lock.acquireUninterruptibly(); | 
|  | Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t1); | 
|  | assertTrue(lock.hasQueuedThreads()); | 
|  | Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t2); | 
|  | assertTrue(lock.hasQueuedThreads()); | 
|  | t1.interrupt(); | 
|  | awaitTermination(t1); | 
|  | assertTrue(lock.hasQueuedThreads()); | 
|  | lock.release(); | 
|  | awaitTermination(t2); | 
|  | assertFalse(lock.hasQueuedThreads()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * getQueueLength reports number of waiting threads | 
|  | */ | 
|  | public void testGetQueueLength()      { testGetQueueLength(false); } | 
|  | public void testGetQueueLength_fair() { testGetQueueLength(true); } | 
|  | public void testGetQueueLength(boolean fair) { | 
|  | final PublicSemaphore lock = new PublicSemaphore(1, fair); | 
|  | assertEquals(0, lock.getQueueLength()); | 
|  | lock.acquireUninterruptibly(); | 
|  | Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t1); | 
|  | assertEquals(1, lock.getQueueLength()); | 
|  | Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t2); | 
|  | assertEquals(2, lock.getQueueLength()); | 
|  | t1.interrupt(); | 
|  | awaitTermination(t1); | 
|  | assertEquals(1, lock.getQueueLength()); | 
|  | lock.release(); | 
|  | awaitTermination(t2); | 
|  | assertEquals(0, lock.getQueueLength()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * getQueuedThreads includes waiting threads | 
|  | */ | 
|  | public void testGetQueuedThreads()      { testGetQueuedThreads(false); } | 
|  | public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); } | 
|  | public void testGetQueuedThreads(boolean fair) { | 
|  | final PublicSemaphore lock = new PublicSemaphore(1, fair); | 
|  | assertTrue(lock.getQueuedThreads().isEmpty()); | 
|  | lock.acquireUninterruptibly(); | 
|  | assertTrue(lock.getQueuedThreads().isEmpty()); | 
|  | Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t1); | 
|  | assertTrue(lock.getQueuedThreads().contains(t1)); | 
|  | Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); | 
|  | waitForQueuedThread(lock, t2); | 
|  | assertTrue(lock.getQueuedThreads().contains(t1)); | 
|  | assertTrue(lock.getQueuedThreads().contains(t2)); | 
|  | t1.interrupt(); | 
|  | awaitTermination(t1); | 
|  | assertFalse(lock.getQueuedThreads().contains(t1)); | 
|  | assertTrue(lock.getQueuedThreads().contains(t2)); | 
|  | lock.release(); | 
|  | awaitTermination(t2); | 
|  | assertTrue(lock.getQueuedThreads().isEmpty()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * drainPermits reports and removes given number of permits | 
|  | */ | 
|  | public void testDrainPermits()      { testDrainPermits(false); } | 
|  | public void testDrainPermits_fair() { testDrainPermits(true); } | 
|  | public void testDrainPermits(boolean fair) { | 
|  | Semaphore s = new Semaphore(0, fair); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertEquals(0, s.drainPermits()); | 
|  | s.release(10); | 
|  | assertEquals(10, s.availablePermits()); | 
|  | assertEquals(10, s.drainPermits()); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertEquals(0, s.drainPermits()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * release(-N) throws IllegalArgumentException | 
|  | */ | 
|  | public void testReleaseIAE()      { testReleaseIAE(false); } | 
|  | public void testReleaseIAE_fair() { testReleaseIAE(true); } | 
|  | public void testReleaseIAE(boolean fair) { | 
|  | Semaphore s = new Semaphore(10, fair); | 
|  | try { | 
|  | s.release(-1); | 
|  | shouldThrow(); | 
|  | } catch (IllegalArgumentException success) {} | 
|  | } | 
|  |  | 
|  | /** | 
|  | * reducePermits(-N) throws IllegalArgumentException | 
|  | */ | 
|  | public void testReducePermitsIAE()      { testReducePermitsIAE(false); } | 
|  | public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); } | 
|  | public void testReducePermitsIAE(boolean fair) { | 
|  | PublicSemaphore s = new PublicSemaphore(10, fair); | 
|  | try { | 
|  | s.reducePermits(-1); | 
|  | shouldThrow(); | 
|  | } catch (IllegalArgumentException success) {} | 
|  | } | 
|  |  | 
|  | /** | 
|  | * reducePermits reduces number of permits | 
|  | */ | 
|  | public void testReducePermits()      { testReducePermits(false); } | 
|  | public void testReducePermits_fair() { testReducePermits(true); } | 
|  | public void testReducePermits(boolean fair) { | 
|  | PublicSemaphore s = new PublicSemaphore(10, fair); | 
|  | assertEquals(10, s.availablePermits()); | 
|  | s.reducePermits(0); | 
|  | assertEquals(10, s.availablePermits()); | 
|  | s.reducePermits(1); | 
|  | assertEquals(9, s.availablePermits()); | 
|  | s.reducePermits(10); | 
|  | assertEquals(-1, s.availablePermits()); | 
|  | s.reducePermits(10); | 
|  | assertEquals(-11, s.availablePermits()); | 
|  | s.reducePermits(0); | 
|  | assertEquals(-11, s.availablePermits()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * a reserialized semaphore has same number of permits and | 
|  | * fairness, but no queued threads | 
|  | */ | 
|  | public void testSerialization()      { testSerialization(false); } | 
|  | public void testSerialization_fair() { testSerialization(true); } | 
|  | public void testSerialization(boolean fair) { | 
|  | try { | 
|  | Semaphore s = new Semaphore(3, fair); | 
|  | s.acquire(); | 
|  | s.acquire(); | 
|  | s.release(); | 
|  |  | 
|  | Semaphore clone = serialClone(s); | 
|  | assertEquals(fair, s.isFair()); | 
|  | assertEquals(fair, clone.isFair()); | 
|  | assertEquals(2, s.availablePermits()); | 
|  | assertEquals(2, clone.availablePermits()); | 
|  | clone.acquire(); | 
|  | clone.acquire(); | 
|  | clone.release(); | 
|  | assertEquals(2, s.availablePermits()); | 
|  | assertEquals(1, clone.availablePermits()); | 
|  | assertFalse(s.hasQueuedThreads()); | 
|  | assertFalse(clone.hasQueuedThreads()); | 
|  | } catch (InterruptedException e) { threadUnexpectedException(e); } | 
|  |  | 
|  | { | 
|  | PublicSemaphore s = new PublicSemaphore(0, fair); | 
|  | Thread t = newStartedThread(new InterruptibleLockRunnable(s)); | 
|  | // waitForQueuedThreads(s); // suffers from "flicker", so ... | 
|  | waitForQueuedThread(s, t);  // ... we use this instead | 
|  | PublicSemaphore clone = serialClone(s); | 
|  | assertEquals(fair, s.isFair()); | 
|  | assertEquals(fair, clone.isFair()); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertEquals(0, clone.availablePermits()); | 
|  | assertTrue(s.hasQueuedThreads()); | 
|  | assertFalse(clone.hasQueuedThreads()); | 
|  | s.release(); | 
|  | awaitTermination(t); | 
|  | assertFalse(s.hasQueuedThreads()); | 
|  | assertFalse(clone.hasQueuedThreads()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * tryAcquire(n) succeeds when sufficient permits, else fails | 
|  | */ | 
|  | public void testTryAcquireNInSameThread()      { testTryAcquireNInSameThread(false); } | 
|  | public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); } | 
|  | public void testTryAcquireNInSameThread(boolean fair) { | 
|  | Semaphore s = new Semaphore(2, fair); | 
|  | assertEquals(2, s.availablePermits()); | 
|  | assertFalse(s.tryAcquire(3)); | 
|  | assertEquals(2, s.availablePermits()); | 
|  | assertTrue(s.tryAcquire(2)); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertFalse(s.tryAcquire(1)); | 
|  | assertFalse(s.tryAcquire(2)); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * acquire succeeds if permits available | 
|  | */ | 
|  | public void testReleaseAcquireSameThread_acquire()       { testReleaseAcquireSameThread(false, AcquireMethod.acquire); } | 
|  | public void testReleaseAcquireSameThread_acquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquire); } | 
|  | public void testReleaseAcquireSameThread_acquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); } | 
|  | public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); } | 
|  | public void testReleaseAcquireSameThread_acquireUninterruptibly()       { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireSameThread_acquireUninterruptibly_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireSameThread_acquireUninterruptiblyN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireSameThread_tryAcquire()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); } | 
|  | public void testReleaseAcquireSameThread_tryAcquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireTimed()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireTimed_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireTimedN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); } | 
|  | public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); } | 
|  | public void testReleaseAcquireSameThread(boolean fair, | 
|  | final AcquireMethod acquirer) { | 
|  | Semaphore s = new Semaphore(1, fair); | 
|  | for (int i = 1; i < 6; i++) { | 
|  | s.release(i); | 
|  | assertEquals(1 + i, s.availablePermits()); | 
|  | try { | 
|  | acquirer.acquire(s, i); | 
|  | } catch (InterruptedException e) { threadUnexpectedException(e); } | 
|  | assertEquals(1, s.availablePermits()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * release in one thread enables acquire in another thread | 
|  | */ | 
|  | public void testReleaseAcquireDifferentThreads_acquire()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); } | 
|  | public void testReleaseAcquireDifferentThreads_acquire_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireUninterruptibly()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } | 
|  | public void testReleaseAcquireDifferentThreads_tryAcquireTimed()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); } | 
|  | public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); } | 
|  | public void testReleaseAcquireDifferentThreads_tryAcquireTimedN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); } | 
|  | public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); } | 
|  | public void testReleaseAcquireDifferentThreads(boolean fair, | 
|  | final AcquireMethod acquirer) { | 
|  | final Semaphore s = new Semaphore(0, fair); | 
|  | final int rounds = 4; | 
|  | long startTime = System.nanoTime(); | 
|  | Thread t = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() throws InterruptedException { | 
|  | for (int i = 0; i < rounds; i++) { | 
|  | assertFalse(s.hasQueuedThreads()); | 
|  | if (i % 2 == 0) | 
|  | acquirer.acquire(s); | 
|  | else | 
|  | acquirer.acquire(s, 3); | 
|  | }}}); | 
|  |  | 
|  | for (int i = 0; i < rounds; i++) { | 
|  | while (! (s.availablePermits() == 0 && s.hasQueuedThreads())) | 
|  | Thread.yield(); | 
|  | assertTrue(t.isAlive()); | 
|  | if (i % 2 == 0) | 
|  | s.release(); | 
|  | else | 
|  | s.release(3); | 
|  | } | 
|  | awaitTermination(t); | 
|  | assertEquals(0, s.availablePermits()); | 
|  | assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * fair locks are strictly FIFO | 
|  | */ | 
|  | public void testFairLocksFifo() { | 
|  | final PublicSemaphore s = new PublicSemaphore(1, true); | 
|  | final CountDownLatch pleaseRelease = new CountDownLatch(1); | 
|  | Thread t1 = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() throws InterruptedException { | 
|  | // Will block; permits are available, but not three | 
|  | s.acquire(3); | 
|  | }}); | 
|  |  | 
|  | waitForQueuedThread(s, t1); | 
|  |  | 
|  | Thread t2 = newStartedThread(new CheckedRunnable() { | 
|  | public void realRun() throws InterruptedException { | 
|  | // Will fail, even though 1 permit is available | 
|  | assertFalse(s.tryAcquire(0L, MILLISECONDS)); | 
|  | assertFalse(s.tryAcquire(1, 0L, MILLISECONDS)); | 
|  |  | 
|  | // untimed tryAcquire will barge and succeed | 
|  | assertTrue(s.tryAcquire()); | 
|  | s.release(2); | 
|  | assertTrue(s.tryAcquire(2)); | 
|  | s.release(); | 
|  |  | 
|  | pleaseRelease.countDown(); | 
|  | // Will queue up behind t1, even though 1 permit is available | 
|  | s.acquire(); | 
|  | }}); | 
|  |  | 
|  | await(pleaseRelease); | 
|  | waitForQueuedThread(s, t2); | 
|  | s.release(2); | 
|  | awaitTermination(t1); | 
|  | assertTrue(t2.isAlive()); | 
|  | s.release(); | 
|  | awaitTermination(t2); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * toString indicates current number of permits | 
|  | */ | 
|  | public void testToString()      { testToString(false); } | 
|  | public void testToString_fair() { testToString(true); } | 
|  | public void testToString(boolean fair) { | 
|  | PublicSemaphore s = new PublicSemaphore(0, fair); | 
|  | assertTrue(s.toString().contains("Permits = 0")); | 
|  | s.release(); | 
|  | assertTrue(s.toString().contains("Permits = 1")); | 
|  | s.release(2); | 
|  | assertTrue(s.toString().contains("Permits = 3")); | 
|  | s.reducePermits(5); | 
|  | assertTrue(s.toString().contains("Permits = -2")); | 
|  | } | 
|  |  | 
|  | } |