| /* |
| * 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")); |
| } |
| |
| } |