/*
* 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 static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestSuite;
public class AbstractQueuedLongSynchronizerTest 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(AbstractQueuedLongSynchronizerTest.class);
// }
/**
* A simple mutex class, adapted from the class javadoc. Exclusive
* acquire tests exercise this as a sample user extension.
*/
static class Mutex extends AbstractQueuedLongSynchronizer {
/** An eccentric value > 32 bits for locked synchronizer state. */
static final long LOCKED = (1L << 63) | (1L << 15);
static final long UNLOCKED = 0;
public boolean isHeldExclusively() {
long state = getState();
assertTrue(state == UNLOCKED || state == LOCKED);
return state == LOCKED;
}
public boolean tryAcquire(long acquires) {
assertEquals(LOCKED, acquires);
return compareAndSetState(UNLOCKED, LOCKED);
}
public boolean tryRelease(long releases) {
if (getState() != LOCKED) throw new IllegalMonitorStateException();
setState(UNLOCKED);
return true;
}
public boolean tryAcquireNanos(long nanos) throws InterruptedException {
return tryAcquireNanos(LOCKED, nanos);
}
public boolean tryAcquire() {
return tryAcquire(LOCKED);
}
public boolean tryRelease() {
return tryRelease(LOCKED);
}
public void acquire() {
acquire(LOCKED);
}
public void acquireInterruptibly() throws InterruptedException {
acquireInterruptibly(LOCKED);
}
public void release() {
release(LOCKED);
}
public ConditionObject newCondition() {
return new ConditionObject();
}
}
/**
* A simple latch class, to test shared mode.
*/
static class BooleanLatch extends AbstractQueuedLongSynchronizer {
public boolean isSignalled() { return getState() != 0; }
public long tryAcquireShared(long ignore) {
return isSignalled() ? 1 : -1;
}
public boolean tryReleaseShared(long ignore) {
setState(1L << 62);
return true;
}
}
/**
* A runnable calling acquireInterruptibly that does not expect to
* be interrupted.
*/
class InterruptibleSyncRunnable extends CheckedRunnable {
final Mutex sync;
InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; }
public void realRun() throws InterruptedException {
sync.acquireInterruptibly();
}
}
/**
* A runnable calling acquireInterruptibly that expects to be
* interrupted.
*/
class InterruptedSyncRunnable extends CheckedInterruptedRunnable {
final Mutex sync;
InterruptedSyncRunnable(Mutex sync) { this.sync = sync; }
public void realRun() throws InterruptedException {
sync.acquireInterruptibly();
}
}
/** A constant to clarify calls to checking methods below. */
static final Thread[] NO_THREADS = new Thread[0];
/**
* Spin-waits until sync.isQueued(t) becomes true.
*/
void waitForQueuedThread(AbstractQueuedLongSynchronizer sync,
Thread t) {
long startTime = System.nanoTime();
while (!sync.isQueued(t)) {
if (millisElapsedSince(startTime) > LONG_DELAY_MS)
throw new AssertionFailedError("timed out");
Thread.yield();
}
assertTrue(t.isAlive());
}
/**
* Checks that sync has exactly the given queued threads.
*/
void assertHasQueuedThreads(AbstractQueuedLongSynchronizer sync,
Thread... expected) {
Collection<Thread> actual = sync.getQueuedThreads();
assertEquals(expected.length > 0, sync.hasQueuedThreads());
assertEquals(expected.length, sync.getQueueLength());
assertEquals(expected.length, actual.size());
assertEquals(expected.length == 0, actual.isEmpty());
assertEquals(new HashSet<Thread>(actual),
new HashSet<Thread>(Arrays.asList(expected)));
}
/**
* Checks that sync has exactly the given (exclusive) queued threads.
*/
void assertHasExclusiveQueuedThreads(AbstractQueuedLongSynchronizer sync,
Thread... expected) {
assertHasQueuedThreads(sync, expected);
assertEquals(new HashSet<Thread>(sync.getExclusiveQueuedThreads()),
new HashSet<Thread>(sync.getQueuedThreads()));
assertEquals(0, sync.getSharedQueuedThreads().size());
assertTrue(sync.getSharedQueuedThreads().isEmpty());
}
/**
* Checks that sync has exactly the given (shared) queued threads.
*/
void assertHasSharedQueuedThreads(AbstractQueuedLongSynchronizer sync,
Thread... expected) {
assertHasQueuedThreads(sync, expected);
assertEquals(new HashSet<Thread>(sync.getSharedQueuedThreads()),
new HashSet<Thread>(sync.getQueuedThreads()));
assertEquals(0, sync.getExclusiveQueuedThreads().size());
assertTrue(sync.getExclusiveQueuedThreads().isEmpty());
}
/**
* Checks that condition c has exactly the given waiter threads,
* after acquiring mutex.
*/
void assertHasWaitersUnlocked(Mutex sync, ConditionObject c,
Thread... threads) {
sync.acquire();
assertHasWaitersLocked(sync, c, threads);
sync.release();
}
/**
* Checks that condition c has exactly the given waiter threads.
*/
void assertHasWaitersLocked(Mutex sync, ConditionObject c,
Thread... threads) {
assertEquals(threads.length > 0, sync.hasWaiters(c));
assertEquals(threads.length, sync.getWaitQueueLength(c));
assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty());
assertEquals(threads.length, sync.getWaitingThreads(c).size());
assertEquals(new HashSet<Thread>(sync.getWaitingThreads(c)),
new HashSet<Thread>(Arrays.asList(threads)));
}
enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
/**
* Awaits condition using the specified AwaitMethod.
*/
void await(ConditionObject c, AwaitMethod awaitMethod)
throws InterruptedException {
long timeoutMillis = 2 * LONG_DELAY_MS;
switch (awaitMethod) {
case await:
c.await();
break;
case awaitTimed:
assertTrue(c.await(timeoutMillis, MILLISECONDS));
break;
case awaitNanos:
long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
long nanosRemaining = c.awaitNanos(nanosTimeout);
assertTrue(nanosRemaining > 0);
break;
case awaitUntil:
assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
break;
default:
throw new AssertionError();
}
}
/**
* Checks that awaiting the given condition times out (using the
* default timeout duration).
*/
void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) {
long timeoutMillis = timeoutMillis();
long startTime;
try {
switch (awaitMethod) {
case awaitTimed:
startTime = System.nanoTime();
assertFalse(c.await(timeoutMillis, MILLISECONDS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitNanos:
startTime = System.nanoTime();
long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
long nanosRemaining = c.awaitNanos(nanosTimeout);
assertTrue(nanosRemaining <= 0);
assertTrue(nanosRemaining > -MILLISECONDS.toNanos(LONG_DELAY_MS));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
break;
case awaitUntil:
// We shouldn't assume that nanoTime and currentTimeMillis
// use the same time source, so don't use nanoTime here.
java.util.Date delayedDate = delayedDate(timeoutMillis());
assertFalse(c.awaitUntil(delayedDate(timeoutMillis)));
assertTrue(new java.util.Date().getTime() >= delayedDate.getTime());
break;
default:
throw new UnsupportedOperationException();
}
} catch (InterruptedException ie) { threadUnexpectedException(ie); }
}
/**
* isHeldExclusively is false upon construction
*/
public void testIsHeldExclusively() {
Mutex sync = new Mutex();
assertFalse(sync.isHeldExclusively());
}
/**
* acquiring released sync succeeds
*/
public void testAcquire() {
Mutex sync = new Mutex();
sync.acquire();
assertTrue(sync.isHeldExclusively());
sync.release();
assertFalse(sync.isHeldExclusively());
}
/**
* tryAcquire on a released sync succeeds
*/
public void testTryAcquire() {
Mutex sync = new Mutex();
assertTrue(sync.tryAcquire());
assertTrue(sync.isHeldExclusively());
sync.release();
assertFalse(sync.isHeldExclusively());
}
/**
* hasQueuedThreads reports whether there are waiting threads
*/
public void testHasQueuedThreads() {
final Mutex sync = new Mutex();
assertFalse(sync.hasQueuedThreads());
sync.acquire();
Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
waitForQueuedThread(sync, t1);
assertTrue(sync.hasQueuedThreads());
Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
waitForQueuedThread(sync, t2);
assertTrue(sync.hasQueuedThreads());
t1.interrupt();
awaitTermination(t1);
assertTrue(sync.hasQueuedThreads());
sync.release();
awaitTermination(t2);
assertFalse(sync.hasQueuedThreads());
}
/**
* isQueued(null) throws NullPointerException
*/
public void testIsQueuedNPE() {
final Mutex sync = new Mutex();
try {
sync.isQueued(null);
shouldThrow();
} catch (NullPointerException success) {}
}
/**
* isQueued reports whether a thread is queued
*/
public void testIsQueued() {
final Mutex sync = new Mutex();
Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
assertFalse(sync.isQueued(t1));
assertFalse(sync.isQueued(t2));
sync.acquire();
t1.start();
waitForQueuedThread(sync, t1);
assertTrue(sync.isQueued(t1));
assertFalse(sync.isQueued(t2));
t2.start();
waitForQueuedThread(sync, t2);
assertTrue(sync.isQueued(t1));
assertTrue(sync.isQueued(t2));
t1.interrupt();
awaitTermination(t1);
assertFalse(sync.isQueued(t1));
assertTrue(sync.isQueued(t2));
sync.release();
awaitTermination(t2);
assertFalse(sync.isQueued(t1));
assertFalse(sync.isQueued(t2));
}
/**
* getFirstQueuedThread returns first waiting thread or null if none
*/
public void testGetFirstQueuedThread() {
final Mutex sync = new Mutex();
assertNull(sync.getFirstQueuedThread());
sync.acquire();
Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
waitForQueuedThread(sync, t1);
assertEquals(t1, sync.getFirstQueuedThread());
Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
waitForQueuedThread(sync, t2);
assertEquals(t1, sync.getFirstQueuedThread());
t1.interrupt();
awaitTermination(t1);
assertEquals(t2, sync.getFirstQueuedThread());
sync.release();
awaitTermination(t2);
assertNull(sync.getFirstQueuedThread());
}
/**
* hasContended reports false if no thread has ever blocked, else true
*/
public void testHasContended() {
final Mutex sync = new Mutex();
assertFalse(sync.hasContended());
sync.acquire();
assertFalse(sync.hasContended());
Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
waitForQueuedThread(sync, t1);
assertTrue(sync.hasContended());
Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
waitForQueuedThread(sync, t2);
assertTrue(sync.hasContended());
t1.interrupt();
awaitTermination(t1);
assertTrue(sync.hasContended());
sync.release();
awaitTermination(t2);
assertTrue(sync.hasContended());
}
/**
* getQueuedThreads returns all waiting threads
*/
public void testGetQueuedThreads() {
final Mutex sync = new Mutex();
Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
sync.acquire();
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
t1.start();
waitForQueuedThread(sync, t1);
assertHasExclusiveQueuedThreads(sync, t1);
assertTrue(sync.getQueuedThreads().contains(t1));
assertFalse(sync.getQueuedThreads().contains(t2));
t2.start();
waitForQueuedThread(sync, t2);
assertHasExclusiveQueuedThreads(sync, t1, t2);
assertTrue(sync.getQueuedThreads().contains(t1));
assertTrue(sync.getQueuedThreads().contains(t2));
t1.interrupt();
awaitTermination(t1);
assertHasExclusiveQueuedThreads(sync, t2);
sync.release();
awaitTermination(t2);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
}
/**
* getExclusiveQueuedThreads returns all exclusive waiting threads
*/
public void testGetExclusiveQueuedThreads() {
final Mutex sync = new Mutex();
Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
sync.acquire();
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
t1.start();
waitForQueuedThread(sync, t1);
assertHasExclusiveQueuedThreads(sync, t1);
assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
assertFalse(sync.getExclusiveQueuedThreads().contains(t2));
t2.start();
waitForQueuedThread(sync, t2);
assertHasExclusiveQueuedThreads(sync, t1, t2);
assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
assertTrue(sync.getExclusiveQueuedThreads().contains(t2));
t1.interrupt();
awaitTermination(t1);
assertHasExclusiveQueuedThreads(sync, t2);
sync.release();
awaitTermination(t2);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
}
/**
* getSharedQueuedThreads does not include exclusively waiting threads
*/
public void testGetSharedQueuedThreads_Exclusive() {
final Mutex sync = new Mutex();
assertTrue(sync.getSharedQueuedThreads().isEmpty());
sync.acquire();
assertTrue(sync.getSharedQueuedThreads().isEmpty());
Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
waitForQueuedThread(sync, t1);
assertTrue(sync.getSharedQueuedThreads().isEmpty());
Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
waitForQueuedThread(sync, t2);
assertTrue(sync.getSharedQueuedThreads().isEmpty());
t1.interrupt();
awaitTermination(t1);
assertTrue(sync.getSharedQueuedThreads().isEmpty());
sync.release();
awaitTermination(t2);
assertTrue(sync.getSharedQueuedThreads().isEmpty());
}
/**
* getSharedQueuedThreads returns all shared waiting threads
*/
public void testGetSharedQueuedThreads_Shared() {
final BooleanLatch l = new BooleanLatch();
assertHasSharedQueuedThreads(l, NO_THREADS);
Thread t1 = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
l.acquireSharedInterruptibly(0);
}});
waitForQueuedThread(l, t1);
assertHasSharedQueuedThreads(l, t1);
Thread t2 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
l.acquireSharedInterruptibly(0);
}});
waitForQueuedThread(l, t2);
assertHasSharedQueuedThreads(l, t1, t2);
t1.interrupt();
awaitTermination(t1);
assertHasSharedQueuedThreads(l, t2);
assertTrue(l.releaseShared(0));
awaitTermination(t2);
assertHasSharedQueuedThreads(l, NO_THREADS);
}
/**
* tryAcquireNanos is interruptible
*/
public void testTryAcquireNanos_Interruptible() {
final Mutex sync = new Mutex();
sync.acquire();
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS));
}});
waitForQueuedThread(sync, t);
t.interrupt();
awaitTermination(t);
}
/**
* tryAcquire on exclusively held sync fails
*/
public void testTryAcquireWhenSynced() {
final Mutex sync = new Mutex();
sync.acquire();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
assertFalse(sync.tryAcquire());
}});
awaitTermination(t);
sync.release();
}
/**
* tryAcquireNanos on an exclusively held sync times out
*/
public void testAcquireNanos_Timeout() {
final Mutex sync = new Mutex();
sync.acquire();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
long startTime = System.nanoTime();
long nanos = MILLISECONDS.toNanos(timeoutMillis());
assertFalse(sync.tryAcquireNanos(nanos));
assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
}});
awaitTermination(t);
sync.release();
}
/**
* getState is true when acquired and false when not
*/
public void testGetState() {
final Mutex sync = new Mutex();
sync.acquire();
assertTrue(sync.isHeldExclusively());
sync.release();
assertFalse(sync.isHeldExclusively());
final BooleanLatch acquired = new BooleanLatch();
final BooleanLatch done = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertTrue(acquired.releaseShared(0));
done.acquireShared(0);
sync.release();
}});
acquired.acquireShared(0);
assertTrue(sync.isHeldExclusively());
assertTrue(done.releaseShared(0));
awaitTermination(t);
assertFalse(sync.isHeldExclusively());
}
/**
* acquireInterruptibly succeeds when released, else is interruptible
*/
public void testAcquireInterruptibly() throws InterruptedException {
final Mutex sync = new Mutex();
final BooleanLatch threadStarted = new BooleanLatch();
sync.acquireInterruptibly();
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
assertTrue(threadStarted.releaseShared(0));
sync.acquireInterruptibly();
}});
threadStarted.acquireShared(0);
waitForQueuedThread(sync, t);
t.interrupt();
awaitTermination(t);
assertTrue(sync.isHeldExclusively());
}
/**
* owns is true for a condition created by sync else false
*/
public void testOwns() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final Mutex sync2 = new Mutex();
assertTrue(sync.owns(c));
assertFalse(sync2.owns(c));
}
/**
* Calling await without holding sync throws IllegalMonitorStateException
*/
public void testAwait_IMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
for (AwaitMethod awaitMethod : AwaitMethod.values()) {
long startTime = System.nanoTime();
try {
await(c, awaitMethod);
shouldThrow();
} catch (IllegalMonitorStateException success) {
} catch (InterruptedException e) { threadUnexpectedException(e); }
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
}
}
/**
* Calling signal without holding sync throws IllegalMonitorStateException
*/
public void testSignal_IMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
try {
c.signal();
shouldThrow();
} catch (IllegalMonitorStateException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* Calling signalAll without holding sync throws IllegalMonitorStateException
*/
public void testSignalAll_IMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
try {
c.signalAll();
shouldThrow();
} catch (IllegalMonitorStateException success) {}
}
/**
* await/awaitNanos/awaitUntil without a signal times out
*/
public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); }
public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); }
public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); }
public void testAwait_Timeout(AwaitMethod awaitMethod) {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
sync.acquire();
assertAwaitTimesOut(c, awaitMethod);
sync.release();
}
/**
* await/awaitNanos/awaitUntil returns when signalled
*/
public void testSignal_await() { testSignal(AwaitMethod.await); }
public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); }
public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); }
public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); }
public void testSignal(final AwaitMethod awaitMethod) {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch acquired = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertTrue(acquired.releaseShared(0));
await(c, awaitMethod);
sync.release();
}});
acquired.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
c.signal();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t);
sync.release();
awaitTermination(t);
}
/**
* hasWaiters(null) throws NullPointerException
*/
public void testHasWaitersNPE() {
final Mutex sync = new Mutex();
try {
sync.hasWaiters(null);
shouldThrow();
} catch (NullPointerException success) {}
}
/**
* getWaitQueueLength(null) throws NullPointerException
*/
public void testGetWaitQueueLengthNPE() {
final Mutex sync = new Mutex();
try {
sync.getWaitQueueLength(null);
shouldThrow();
} catch (NullPointerException success) {}
}
/**
* getWaitingThreads throws NPE if null
*/
public void testGetWaitingThreadsNPE() {
final Mutex sync = new Mutex();
try {
sync.getWaitingThreads(null);
shouldThrow();
} catch (NullPointerException success) {}
}
/**
* hasWaiters throws IllegalArgumentException if not owned
*/
public void testHasWaitersIAE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final Mutex sync2 = new Mutex();
try {
sync2.hasWaiters(c);
shouldThrow();
} catch (IllegalArgumentException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* hasWaiters throws IllegalMonitorStateException if not synced
*/
public void testHasWaitersIMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
try {
sync.hasWaiters(c);
shouldThrow();
} catch (IllegalMonitorStateException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitQueueLength throws IllegalArgumentException if not owned
*/
public void testGetWaitQueueLengthIAE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final Mutex sync2 = new Mutex();
try {
sync2.getWaitQueueLength(c);
shouldThrow();
} catch (IllegalArgumentException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitQueueLength throws IllegalMonitorStateException if not synced
*/
public void testGetWaitQueueLengthIMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
try {
sync.getWaitQueueLength(c);
shouldThrow();
} catch (IllegalMonitorStateException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitingThreads throws IllegalArgumentException if not owned
*/
public void testGetWaitingThreadsIAE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final Mutex sync2 = new Mutex();
try {
sync2.getWaitingThreads(c);
shouldThrow();
} catch (IllegalArgumentException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitingThreads throws IllegalMonitorStateException if not synced
*/
public void testGetWaitingThreadsIMSE() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
try {
sync.getWaitingThreads(c);
shouldThrow();
} catch (IllegalMonitorStateException success) {}
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* hasWaiters returns true when a thread is waiting, else false
*/
public void testHasWaiters() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch acquired = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertFalse(sync.hasWaiters(c));
assertTrue(acquired.releaseShared(0));
c.await();
sync.release();
}});
acquired.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
assertTrue(sync.hasWaiters(c));
c.signal();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t);
assertFalse(sync.hasWaiters(c));
sync.release();
awaitTermination(t);
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitQueueLength returns number of waiting threads
*/
public void testGetWaitQueueLength() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch acquired1 = new BooleanLatch();
final BooleanLatch acquired2 = new BooleanLatch();
final Thread t1 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertEquals(0, sync.getWaitQueueLength(c));
assertTrue(acquired1.releaseShared(0));
c.await();
sync.release();
}});
acquired1.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t1);
assertEquals(1, sync.getWaitQueueLength(c));
sync.release();
final Thread t2 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertHasWaitersLocked(sync, c, t1);
assertEquals(1, sync.getWaitQueueLength(c));
assertTrue(acquired2.releaseShared(0));
c.await();
sync.release();
}});
acquired2.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t1, t2);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
assertEquals(2, sync.getWaitQueueLength(c));
c.signalAll();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t1, t2);
assertEquals(0, sync.getWaitQueueLength(c));
sync.release();
awaitTermination(t1);
awaitTermination(t2);
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* getWaitingThreads returns only and all waiting threads
*/
public void testGetWaitingThreads() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch acquired1 = new BooleanLatch();
final BooleanLatch acquired2 = new BooleanLatch();
final Thread t1 = new Thread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertTrue(sync.getWaitingThreads(c).isEmpty());
assertTrue(acquired1.releaseShared(0));
c.await();
sync.release();
}});
final Thread t2 = new Thread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertHasWaitersLocked(sync, c, t1);
assertTrue(sync.getWaitingThreads(c).contains(t1));
assertFalse(sync.getWaitingThreads(c).isEmpty());
assertEquals(1, sync.getWaitingThreads(c).size());
assertTrue(acquired2.releaseShared(0));
c.await();
sync.release();
}});
sync.acquire();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertFalse(sync.getWaitingThreads(c).contains(t1));
assertFalse(sync.getWaitingThreads(c).contains(t2));
assertTrue(sync.getWaitingThreads(c).isEmpty());
assertEquals(0, sync.getWaitingThreads(c).size());
sync.release();
t1.start();
acquired1.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t1);
assertTrue(sync.getWaitingThreads(c).contains(t1));
assertFalse(sync.getWaitingThreads(c).contains(t2));
assertFalse(sync.getWaitingThreads(c).isEmpty());
assertEquals(1, sync.getWaitingThreads(c).size());
sync.release();
t2.start();
acquired2.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t1, t2);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
assertTrue(sync.getWaitingThreads(c).contains(t1));
assertTrue(sync.getWaitingThreads(c).contains(t2));
assertFalse(sync.getWaitingThreads(c).isEmpty());
assertEquals(2, sync.getWaitingThreads(c).size());
c.signalAll();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t1, t2);
assertFalse(sync.getWaitingThreads(c).contains(t1));
assertFalse(sync.getWaitingThreads(c).contains(t2));
assertTrue(sync.getWaitingThreads(c).isEmpty());
assertEquals(0, sync.getWaitingThreads(c).size());
sync.release();
awaitTermination(t1);
awaitTermination(t2);
assertHasWaitersUnlocked(sync, c, NO_THREADS);
}
/**
* awaitUninterruptibly is uninterruptible
*/
public void testAwaitUninterruptibly() {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch pleaseInterrupt = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
sync.acquire();
assertTrue(pleaseInterrupt.releaseShared(0));
c.awaitUninterruptibly();
assertTrue(Thread.interrupted());
assertHasWaitersLocked(sync, c, NO_THREADS);
sync.release();
}});
pleaseInterrupt.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t);
sync.release();
t.interrupt();
assertHasWaitersUnlocked(sync, c, t);
assertThreadStaysAlive(t);
sync.acquire();
assertHasWaitersLocked(sync, c, t);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
c.signal();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t);
sync.release();
awaitTermination(t);
}
/**
* await/awaitNanos/awaitUntil is interruptible
*/
public void testInterruptible_await() { testInterruptible(AwaitMethod.await); }
public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); }
public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); }
public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); }
public void testInterruptible(final AwaitMethod awaitMethod) {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch pleaseInterrupt = new BooleanLatch();
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
assertTrue(pleaseInterrupt.releaseShared(0));
await(c, awaitMethod);
}});
pleaseInterrupt.acquireShared(0);
t.interrupt();
awaitTermination(t);
}
/**
* signalAll wakes up all threads
*/
public void testSignalAll_await() { testSignalAll(AwaitMethod.await); }
public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); }
public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); }
public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); }
public void testSignalAll(final AwaitMethod awaitMethod) {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
final BooleanLatch acquired1 = new BooleanLatch();
final BooleanLatch acquired2 = new BooleanLatch();
Thread t1 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
acquired1.releaseShared(0);
await(c, awaitMethod);
sync.release();
}});
Thread t2 = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
sync.acquire();
acquired2.releaseShared(0);
await(c, awaitMethod);
sync.release();
}});
acquired1.acquireShared(0);
acquired2.acquireShared(0);
sync.acquire();
assertHasWaitersLocked(sync, c, t1, t2);
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
c.signalAll();
assertHasWaitersLocked(sync, c, NO_THREADS);
assertHasExclusiveQueuedThreads(sync, t1, t2);
sync.release();
awaitTermination(t1);
awaitTermination(t2);
}
/**
* toString indicates current state
*/
public void testToString() {
Mutex sync = new Mutex();
assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED));
sync.acquire();
assertTrue(sync.toString().contains("State = " + Mutex.LOCKED));
}
/**
* A serialized AQS deserializes with current state, but no queued threads
*/
public void testSerialization() {
Mutex sync = new Mutex();
assertFalse(serialClone(sync).isHeldExclusively());
sync.acquire();
Thread t = newStartedThread(new InterruptedSyncRunnable(sync));
waitForQueuedThread(sync, t);
assertTrue(sync.isHeldExclusively());
Mutex clone = serialClone(sync);
assertTrue(clone.isHeldExclusively());
assertHasExclusiveQueuedThreads(sync, t);
assertHasExclusiveQueuedThreads(clone, NO_THREADS);
t.interrupt();
awaitTermination(t);
sync.release();
assertFalse(sync.isHeldExclusively());
assertTrue(clone.isHeldExclusively());
assertHasExclusiveQueuedThreads(sync, NO_THREADS);
assertHasExclusiveQueuedThreads(clone, NO_THREADS);
}
/**
* tryReleaseShared setting state changes getState
*/
public void testGetStateWithReleaseShared() {
final BooleanLatch l = new BooleanLatch();
assertFalse(l.isSignalled());
assertTrue(l.releaseShared(0));
assertTrue(l.isSignalled());
}
/**
* releaseShared has no effect when already signalled
*/
public void testReleaseShared() {
final BooleanLatch l = new BooleanLatch();
assertFalse(l.isSignalled());
assertTrue(l.releaseShared(0));
assertTrue(l.isSignalled());
assertTrue(l.releaseShared(0));
assertTrue(l.isSignalled());
}
/**
* acquireSharedInterruptibly returns after release, but not before
*/
public void testAcquireSharedInterruptibly() {
final BooleanLatch l = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
l.acquireSharedInterruptibly(0);
assertTrue(l.isSignalled());
l.acquireSharedInterruptibly(0);
assertTrue(l.isSignalled());
}});
waitForQueuedThread(l, t);
assertFalse(l.isSignalled());
assertThreadStaysAlive(t);
assertHasSharedQueuedThreads(l, t);
assertTrue(l.releaseShared(0));
assertTrue(l.isSignalled());
awaitTermination(t);
}
/**
* tryAcquireSharedNanos returns after release, but not before
*/
public void testTryAcquireSharedNanos() {
final BooleanLatch l = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
assertTrue(l.tryAcquireSharedNanos(0, nanos));
assertTrue(l.isSignalled());
assertTrue(l.tryAcquireSharedNanos(0, nanos));
assertTrue(l.isSignalled());
}});
waitForQueuedThread(l, t);
assertFalse(l.isSignalled());
assertThreadStaysAlive(t);
assertTrue(l.releaseShared(0));
assertTrue(l.isSignalled());
awaitTermination(t);
}
/**
* acquireSharedInterruptibly is interruptible
*/
public void testAcquireSharedInterruptibly_Interruptible() {
final BooleanLatch l = new BooleanLatch();
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
l.acquireSharedInterruptibly(0);
}});
waitForQueuedThread(l, t);
assertFalse(l.isSignalled());
t.interrupt();
awaitTermination(t);
assertFalse(l.isSignalled());
}
/**
* tryAcquireSharedNanos is interruptible
*/
public void testTryAcquireSharedNanos_Interruptible() {
final BooleanLatch l = new BooleanLatch();
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
l.tryAcquireSharedNanos(0, nanos);
}});
waitForQueuedThread(l, t);
assertFalse(l.isSignalled());
t.interrupt();
awaitTermination(t);
assertFalse(l.isSignalled());
}
/**
* tryAcquireSharedNanos times out if not released before timeout
*/
public void testTryAcquireSharedNanos_Timeout() {
final BooleanLatch l = new BooleanLatch();
final BooleanLatch observedQueued = new BooleanLatch();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
assertFalse(l.isSignalled());
for (long millis = timeoutMillis();
!observedQueued.isSignalled();
millis *= 2) {
long nanos = MILLISECONDS.toNanos(millis);
long startTime = System.nanoTime();
assertFalse(l.tryAcquireSharedNanos(0, nanos));
assertTrue(millisElapsedSince(startTime) >= millis);
}
assertFalse(l.isSignalled());
}});
waitForQueuedThread(l, t);
observedQueued.releaseShared(0);
assertFalse(l.isSignalled());
awaitTermination(t);
assertFalse(l.isSignalled());
}
/**
* awaitNanos/timed await with 0 wait times out immediately
*/
public void testAwait_Zero() throws InterruptedException {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
sync.acquire();
assertTrue(c.awaitNanos(0L) <= 0);
assertFalse(c.await(0L, NANOSECONDS));
sync.release();
}
/**
* awaitNanos/timed await with maximum negative wait times does not underflow
*/
public void testAwait_NegativeInfinity() throws InterruptedException {
final Mutex sync = new Mutex();
final ConditionObject c = sync.newCondition();
sync.acquire();
assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0);
assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS));
sync.release();
}
}