--- a/jdk/test/java/util/concurrent/tck/StampedLockTest.java Mon Aug 15 09:04:40 2016 -0700
+++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java Mon Aug 15 09:09:00 2016 -0700
@@ -34,10 +34,12 @@
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;
@@ -57,207 +59,188 @@
}
/**
- * A runnable calling writeLockInterruptibly
+ * Releases write lock, checking isWriteLocked before and after
*/
- class InterruptibleLockRunnable extends CheckedRunnable {
- final StampedLock lock;
- InterruptibleLockRunnable(StampedLock l) { lock = l; }
- public void realRun() throws InterruptedException {
- lock.writeLockInterruptibly();
- }
+ void releaseWriteLock(StampedLock lock, long stamp) {
+ assertTrue(lock.isWriteLocked());
+ assertValid(lock, stamp);
+ lock.unlockWrite(stamp);
+ assertFalse(lock.isWriteLocked());
+ assertFalse(lock.validate(stamp));
}
/**
- * A runnable calling writeLockInterruptibly that expects to be
- * interrupted
+ * Releases read lock, checking isReadLocked before and after
*/
- class InterruptedLockRunnable extends CheckedInterruptedRunnable {
- final StampedLock lock;
- InterruptedLockRunnable(StampedLock l) { lock = l; }
- public void realRun() throws InterruptedException {
- lock.writeLockInterruptibly();
- }
+ void releaseReadLock(StampedLock lock, long stamp) {
+ assertTrue(lock.isReadLocked());
+ assertValid(lock, stamp);
+ lock.unlockRead(stamp);
+ assertFalse(lock.isReadLocked());
+ assertTrue(lock.validate(stamp));
+ }
+
+ long assertNonZero(long v) {
+ assertTrue(v != 0L);
+ return v;
+ }
+
+ long assertValid(StampedLock lock, long stamp) {
+ assertTrue(stamp != 0L);
+ assertTrue(lock.validate(stamp));
+ return stamp;
+ }
+
+ void assertUnlocked(StampedLock lock) {
+ assertFalse(lock.isReadLocked());
+ assertFalse(lock.isWriteLocked());
+ assertEquals(0, lock.getReadLockCount());
+ assertValid(lock, lock.tryOptimisticRead());
+ }
+
+ List<Action> lockLockers(Lock lock) {
+ List<Action> lockers = new ArrayList<>();
+ lockers.add(() -> lock.lock());
+ lockers.add(() -> lock.lockInterruptibly());
+ lockers.add(() -> lock.tryLock());
+ lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS));
+ lockers.add(() -> lock.tryLock(0L, DAYS));
+ lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS));
+ return lockers;
}
- /**
- * Releases write lock, checking isWriteLocked before and after
- */
- void releaseWriteLock(StampedLock lock, long s) {
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
- assertFalse(lock.isWriteLocked());
+ List<Function<StampedLock, Long>> readLockers() {
+ List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
+ readLockers.add((sl) -> sl.readLock());
+ readLockers.add((sl) -> sl.tryReadLock());
+ readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
+ readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+ readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0L, DAYS));
+ readLockers.add((sl) -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
+ return readLockers;
+ }
+
+ List<BiConsumer<StampedLock, Long>> readUnlockers() {
+ List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
+ readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
+ readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
+ readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
+ readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+ readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
+ return readUnlockers;
+ }
+
+ List<Function<StampedLock, Long>> writeLockers() {
+ List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
+ writeLockers.add((sl) -> sl.writeLock());
+ writeLockers.add((sl) -> sl.tryWriteLock());
+ writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0L, DAYS));
+ writeLockers.add((sl) -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
+ return writeLockers;
+ }
+
+ List<BiConsumer<StampedLock, Long>> writeUnlockers() {
+ List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
+ writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
+ writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
+ writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
+ writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+ writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
+ return writeUnlockers;
}
/**
* Constructed StampedLock is in unlocked state
*/
public void testConstructor() {
- StampedLock lock;
- lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
+ assertUnlocked(new StampedLock());
}
/**
- * write-locking and read-locking an unlocked lock succeed
+ * write-locking, then unlocking, an unlocked lock succeed
*/
- public void testLock() {
+ public void testWriteLock_lockUnlock() {
StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- lock.unlockWrite(s);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- lock.unlockRead(rs);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
- /**
- * unlock releases either a read or write lock
- */
- public void testUnlock() {
- StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- lock.unlock(s);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- lock.unlock(rs);
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ assertFalse(lock.isWriteLocked());
+ assertFalse(lock.isReadLocked());
+ assertEquals(0, lock.getReadLockCount());
+
+ long s = writeLocker.apply(lock);
+ assertValid(lock, s);
+ assertTrue(lock.isWriteLocked());
+ assertFalse(lock.isReadLocked());
+ assertEquals(0, lock.getReadLockCount());
+ writeUnlocker.accept(lock, s);
+ assertUnlocked(lock);
+ }
}
/**
- * tryUnlockRead/Write succeeds if locked in associated mode else
- * returns false
+ * read-locking, then unlocking, an unlocked lock succeed
*/
- public void testTryUnlock() {
+ public void testReadLock_lockUnlock() {
StampedLock lock = new StampedLock();
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long s = lock.writeLock();
- assertTrue(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- assertFalse(lock.tryUnlockRead());
- assertTrue(lock.tryUnlockWrite());
- assertFalse(lock.tryUnlockWrite());
- assertFalse(lock.tryUnlockRead());
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- long rs = lock.readLock();
- assertFalse(lock.isWriteLocked());
- assertTrue(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 1);
- assertFalse(lock.tryUnlockWrite());
- assertTrue(lock.tryUnlockRead());
- assertFalse(lock.tryUnlockRead());
- assertFalse(lock.tryUnlockWrite());
- assertFalse(lock.isWriteLocked());
- assertFalse(lock.isReadLocked());
- assertEquals(lock.getReadLockCount(), 0);
- }
- /**
- * write-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testWriteUnlock_IMSE() {
- StampedLock lock = new StampedLock();
- try {
- lock.unlockWrite(0L);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
+ for (Function<StampedLock, Long> readLocker : readLockers())
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ long s = 42;
+ for (int i = 0; i < 2; i++) {
+ s = assertValid(lock, readLocker.apply(lock));
+ assertFalse(lock.isWriteLocked());
+ assertTrue(lock.isReadLocked());
+ assertEquals(i + 1, lock.getReadLockCount());
+ }
+ for (int i = 0; i < 2; i++) {
+ assertFalse(lock.isWriteLocked());
+ assertTrue(lock.isReadLocked());
+ assertEquals(2 - i, lock.getReadLockCount());
+ readUnlocker.accept(lock, s);
+ }
+ assertUnlocked(lock);
+ }
}
/**
- * write-unlocking an unlocked lock throws IllegalMonitorStateException
+ * tryUnlockWrite fails if not write locked
*/
- public void testWriteUnlock_IMSE2() {
+ public void testTryUnlockWrite_failure() {
StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- lock.unlockWrite(s);
- try {
- lock.unlockWrite(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
+ assertFalse(lock.tryUnlockWrite());
- /**
- * write-unlocking after readlock throws IllegalMonitorStateException
- */
- public void testWriteUnlock_IMSE3() {
- StampedLock lock = new StampedLock();
- long s = lock.readLock();
- try {
- lock.unlockWrite(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
+ for (Function<StampedLock, Long> readLocker : readLockers())
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ long s = assertValid(lock, readLocker.apply(lock));
+ assertFalse(lock.tryUnlockWrite());
+ assertTrue(lock.isReadLocked());
+ readUnlocker.accept(lock, s);
+ assertUnlocked(lock);
+ }
}
/**
- * read-unlocking an unlocked lock throws IllegalMonitorStateException
+ * tryUnlockRead fails if not read locked
*/
- public void testReadUnlock_IMSE() {
+ public void testTryUnlockRead_failure() {
StampedLock lock = new StampedLock();
- long s = lock.readLock();
- lock.unlockRead(s);
- try {
- lock.unlockRead(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
+ assertFalse(lock.tryUnlockRead());
+
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ long s = writeLocker.apply(lock);
+ assertFalse(lock.tryUnlockRead());
+ assertTrue(lock.isWriteLocked());
+ writeUnlocker.accept(lock, s);
+ assertUnlocked(lock);
+ }
}
/**
- * read-unlocking an unlocked lock throws IllegalMonitorStateException
- */
- public void testReadUnlock_IMSE2() {
- StampedLock lock = new StampedLock();
- try {
- lock.unlockRead(0L);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * read-unlocking after writeLock throws IllegalMonitorStateException
- */
- public void testReadUnlock_IMSE3() {
- StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- try {
- lock.unlockRead(s);
- shouldThrow();
- } catch (IllegalMonitorStateException success) {}
- }
-
- /**
- * validate(0) fails
+ * validate(0L) fails
*/
public void testValidate0() {
StampedLock lock = new StampedLock();
@@ -265,29 +248,24 @@
}
/**
- * A stamp obtained from a successful lock operation validates
+ * A stamp obtained from a successful lock operation validates while the lock is held
*/
public void testValidate() throws InterruptedException {
StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- s = lock.readLock();
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockRead(s);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
+
+ for (Function<StampedLock, Long> readLocker : readLockers())
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ long s = assertNonZero(readLocker.apply(lock));
+ assertTrue(lock.validate(s));
+ readUnlocker.accept(lock, s);
+ }
+
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ long s = assertNonZero(writeLocker.apply(lock));
+ assertTrue(lock.validate(s));
+ writeUnlocker.accept(lock, s);
+ }
}
/**
@@ -295,124 +273,190 @@
*/
public void testValidate2() throws InterruptedException {
StampedLock lock = new StampedLock();
- long s;
- assertTrue((s = lock.writeLock()) != 0L);
+ long s = assertNonZero(lock.writeLock());
assertTrue(lock.validate(s));
assertFalse(lock.validate(lock.tryWriteLock()));
- assertFalse(lock.validate(lock.tryWriteLock(10L, MILLISECONDS)));
+ assertFalse(lock.validate(lock.tryWriteLock(0L, SECONDS)));
assertFalse(lock.validate(lock.tryReadLock()));
- assertFalse(lock.validate(lock.tryReadLock(10L, MILLISECONDS)));
+ assertFalse(lock.validate(lock.tryReadLock(0L, SECONDS)));
assertFalse(lock.validate(lock.tryOptimisticRead()));
lock.unlockWrite(s);
}
- /**
- * writeLockInterruptibly is interruptible
- */
- public void testWriteLockInterruptibly_Interruptible()
- throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.writeLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
+ void assertThrowInterruptedExceptionWhenPreInterrupted(Action[] actions) {
+ for (Action action : actions) {
+ Thread.currentThread().interrupt();
+ try {
+ action.run();
+ shouldThrow();
+ }
+ catch (InterruptedException success) {}
+ catch (Throwable fail) { threadUnexpectedException(fail); }
+ assertFalse(Thread.interrupted());
+ }
}
/**
- * timed tryWriteLock is interruptible
+ * interruptible operations throw InterruptedException when pre-interrupted
*/
- public void testWriteTryLock_Interruptible() throws InterruptedException {
+ public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() {
+ final CountDownLatch running = new CountDownLatch(1);
+ final StampedLock lock = new StampedLock();
+
+ Action[] interruptibleLockActions = {
+ () -> lock.writeLockInterruptibly(),
+ () -> lock.tryWriteLock(Long.MIN_VALUE, DAYS),
+ () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
+ () -> lock.readLockInterruptibly(),
+ () -> lock.tryReadLock(Long.MIN_VALUE, DAYS),
+ () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
+ () -> lock.asWriteLock().lockInterruptibly(),
+ () -> lock.asWriteLock().tryLock(0L, DAYS),
+ () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
+ () -> lock.asReadLock().lockInterruptibly(),
+ () -> lock.asReadLock().tryLock(0L, DAYS),
+ () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
+ };
+ shuffle(interruptibleLockActions);
+
+ assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
+ {
+ long s = lock.writeLock();
+ assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
+ lock.unlockWrite(s);
+ }
+ {
+ long s = lock.readLock();
+ assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
+ lock.unlockRead(s);
+ }
+ }
+
+ void assertThrowInterruptedExceptionWhenInterrupted(Action[] actions) {
+ int n = actions.length;
+ Future<?>[] futures = new Future<?>[n];
+ CountDownLatch threadsStarted = new CountDownLatch(n);
+ CountDownLatch done = new CountDownLatch(n);
+
+ for (int i = 0; i < n; i++) {
+ Action action = actions[i];
+ futures[i] = cachedThreadPool.submit(new CheckedRunnable() {
+ public void realRun() throws Throwable {
+ threadsStarted.countDown();
+ try {
+ action.run();
+ shouldThrow();
+ }
+ catch (InterruptedException success) {}
+ catch (Throwable fail) { threadUnexpectedException(fail); }
+ assertFalse(Thread.interrupted());
+ done.countDown();
+ }});
+ }
+
+ await(threadsStarted);
+ assertEquals(n, done.getCount());
+ for (Future<?> future : futures) // Interrupt all the tasks
+ future.cancel(true);
+ await(done);
+ }
+
+ /**
+ * interruptible operations throw InterruptedException when write locked and interrupted
+ */
+ public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
final CountDownLatch running = new CountDownLatch(1);
final StampedLock lock = new StampedLock();
long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS);
- }});
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
+ Action[] interruptibleLockBlockingActions = {
+ () -> lock.writeLockInterruptibly(),
+ () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
+ () -> lock.readLockInterruptibly(),
+ () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
+ () -> lock.asWriteLock().lockInterruptibly(),
+ () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
+ () -> lock.asReadLock().lockInterruptibly(),
+ () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
+ };
+ shuffle(interruptibleLockBlockingActions);
+
+ assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
}
/**
- * readLockInterruptibly is interruptible
+ * interruptible operations throw InterruptedException when read locked and interrupted
*/
- public void testReadLockInterruptibly_Interruptible()
- throws InterruptedException {
+ public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
final CountDownLatch running = new CountDownLatch(1);
final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.readLockInterruptibly();
- }});
+ long s = lock.readLock();
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
+ Action[] interruptibleLockBlockingActions = {
+ () -> lock.writeLockInterruptibly(),
+ () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
+ () -> lock.asWriteLock().lockInterruptibly(),
+ () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
+ };
+ shuffle(interruptibleLockBlockingActions);
+
+ assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
}
/**
- * timed tryReadLock is interruptible
+ * Non-interruptible operations ignore and preserve interrupt status
*/
- public void testReadTryLock_Interruptible() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
+ public void testNonInterruptibleOperationsIgnoreInterrupts() {
final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS);
- }});
+ Thread.currentThread().interrupt();
+
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ long s = assertValid(lock, lock.readLock());
+ readUnlocker.accept(lock, s);
+ s = assertValid(lock, lock.tryReadLock());
+ readUnlocker.accept(lock, s);
+ }
+
+ lock.asReadLock().lock();
+ lock.asReadLock().unlock();
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ long s = assertValid(lock, lock.writeLock());
+ writeUnlocker.accept(lock, s);
+ s = assertValid(lock, lock.tryWriteLock());
+ writeUnlocker.accept(lock, s);
+ }
+
+ lock.asWriteLock().lock();
+ lock.asWriteLock().unlock();
+
+ assertTrue(Thread.interrupted());
}
/**
* tryWriteLock on an unlocked lock succeeds
*/
- public void testWriteTryLock() {
+ public void testTryWriteLock() {
final StampedLock lock = new StampedLock();
long s = lock.tryWriteLock();
assertTrue(s != 0L);
assertTrue(lock.isWriteLocked());
- long s2 = lock.tryWriteLock();
- assertEquals(s2, 0L);
+ assertEquals(0L, lock.tryWriteLock());
releaseWriteLock(lock, s);
}
/**
* tryWriteLock fails if locked
*/
- public void testWriteTryLockWhenLocked() {
+ public void testTryWriteLockWhenLocked() {
final StampedLock lock = new StampedLock();
long s = lock.writeLock();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
- long ws = lock.tryWriteLock();
- assertTrue(ws == 0L);
+ assertEquals(0L, lock.tryWriteLock());
}});
+ assertEquals(0L, lock.tryWriteLock());
awaitTermination(t);
releaseWriteLock(lock, s);
}
@@ -420,15 +464,15 @@
/**
* tryReadLock fails if write-locked
*/
- public void testReadTryLockWhenLocked() {
+ public void testTryReadLockWhenLocked() {
final StampedLock lock = new StampedLock();
long s = lock.writeLock();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
- long rs = lock.tryReadLock();
- assertEquals(rs, 0L);
+ assertEquals(0L, lock.tryReadLock());
}});
+ assertEquals(0L, lock.tryReadLock());
awaitTermination(t);
releaseWriteLock(lock, s);
}
@@ -442,13 +486,20 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() throws InterruptedException {
long s2 = lock.tryReadLock();
- assertTrue(s2 != 0L);
+ assertValid(lock, s2);
lock.unlockRead(s2);
long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
- assertTrue(s3 != 0L);
+ assertValid(lock, s3);
lock.unlockRead(s3);
long s4 = lock.readLock();
+ assertValid(lock, s4);
lock.unlockRead(s4);
+ lock.asReadLock().lock();
+ lock.asReadLock().unlock();
+ lock.asReadLock().lockInterruptibly();
+ lock.asReadLock().unlock();
+ lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
+ lock.asReadLock().unlock();
}});
awaitTermination(t);
@@ -470,7 +521,7 @@
}});
running.await();
- waitForThreadToEnterWaitState(t, 100);
+ waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS);
assertFalse(lock.isWriteLocked());
lock.unlockRead(rs);
awaitTermination(t);
@@ -497,6 +548,7 @@
lock.unlockWrite(ws);
}});
+ assertTrue(lock.isReadLocked());
assertFalse(lock.isWriteLocked());
lock.unlockRead(s);
awaitTermination(t2);
@@ -508,25 +560,31 @@
*/
public void testReadAfterWriteLock() {
final StampedLock lock = new StampedLock();
+ final CountDownLatch threadsStarted = new CountDownLatch(2);
final long s = lock.writeLock();
Thread t1 = newStartedThread(new CheckedRunnable() {
public void realRun() {
+ threadsStarted.countDown();
long rs = lock.readLock();
lock.unlockRead(rs);
}});
Thread t2 = newStartedThread(new CheckedRunnable() {
public void realRun() {
+ threadsStarted.countDown();
long rs = lock.readLock();
lock.unlockRead(rs);
}});
+ await(threadsStarted);
+ waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS);
+ waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS);
releaseWriteLock(lock, s);
awaitTermination(t1);
awaitTermination(t2);
}
/**
- * tryReadLock succeeds if readlocked but not writelocked
+ * tryReadLock succeeds if read locked but not write locked
*/
public void testTryLockWhenReadLocked() {
final StampedLock lock = new StampedLock();
@@ -534,7 +592,7 @@
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
long rs = lock.tryReadLock();
- threadAssertTrue(rs != 0L);
+ assertValid(lock, rs);
lock.unlockRead(rs);
}});
@@ -543,15 +601,14 @@
}
/**
- * tryWriteLock fails when readlocked
+ * tryWriteLock fails when read locked
*/
- public void testWriteTryLockWhenReadLocked() {
+ public void testTryWriteLockWhenReadLocked() {
final StampedLock lock = new StampedLock();
long s = lock.readLock();
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
- long ws = lock.tryWriteLock();
- threadAssertEquals(ws, 0L);
+ threadAssertEquals(0L, lock.tryWriteLock());
}});
awaitTermination(t);
@@ -559,86 +616,82 @@
}
/**
- * timed tryWriteLock times out if locked
+ * timed lock operations time out if lock not available
*/
- public void testWriteTryLock_Timeout() {
+ public void testTimedLock_Timeout() throws Exception {
+ ArrayList<Future<?>> futures = new ArrayList<>();
+
+ // Write locked
final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
+ long stamp = lock.writeLock();
+ assertEquals(0L, lock.tryReadLock(0L, DAYS));
+ assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
+ assertFalse(lock.asReadLock().tryLock(0L, DAYS));
+ assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
+ assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
+ assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
+
+ futures.add(cachedThreadPool.submit(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }}));
+
+ futures.add(cachedThreadPool.submit(new CheckedRunnable() {
public void realRun() throws InterruptedException {
long startTime = System.nanoTime();
- long timeoutMillis = 10;
- long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
- assertEquals(ws, 0L);
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- }});
+ assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }}));
+
+ // Read locked
+ final StampedLock lock2 = new StampedLock();
+ long stamp2 = lock2.readLock();
+ assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
+ assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
+ assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
+ assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
- awaitTermination(t);
+ futures.add(cachedThreadPool.submit(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }}));
+
+ for (Future<?> future : futures)
+ assertNull(future.get());
+
+ releaseWriteLock(lock, stamp);
+ releaseReadLock(lock2, stamp2);
+ }
+
+ /**
+ * writeLockInterruptibly succeeds if unlocked
+ */
+ public void testWriteLockInterruptibly() throws InterruptedException {
+ final StampedLock lock = new StampedLock();
+ long s = lock.writeLockInterruptibly();
+ assertTrue(lock.isWriteLocked());
releaseWriteLock(lock, s);
}
/**
- * timed tryReadLock times out if write-locked
- */
- public void testReadTryLock_Timeout() {
- final StampedLock lock = new StampedLock();
- long s = lock.writeLock();
- Thread t = newStartedThread(new CheckedRunnable() {
- public void realRun() throws InterruptedException {
- long startTime = System.nanoTime();
- long timeoutMillis = 10;
- long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
- assertEquals(rs, 0L);
- assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
- }});
-
- awaitTermination(t);
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
- }
-
- /**
- * writeLockInterruptibly succeeds if unlocked, else is interruptible
- */
- public void testWriteLockInterruptibly() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
- final StampedLock lock = new StampedLock();
- long s = lock.writeLockInterruptibly();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.writeLockInterruptibly();
- }});
-
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- assertTrue(lock.isWriteLocked());
- awaitTermination(t);
- releaseWriteLock(lock, s);
- }
-
- /**
- * readLockInterruptibly succeeds if lock free else is interruptible
+ * readLockInterruptibly succeeds if lock free
*/
public void testReadLockInterruptibly() throws InterruptedException {
- final CountDownLatch running = new CountDownLatch(1);
final StampedLock lock = new StampedLock();
- long s;
- s = lock.readLockInterruptibly();
+
+ long s = assertValid(lock, lock.readLockInterruptibly());
+ assertTrue(lock.isReadLocked());
lock.unlockRead(s);
- s = lock.writeLockInterruptibly();
- Thread t = newStartedThread(new CheckedInterruptedRunnable() {
- public void realRun() throws InterruptedException {
- running.countDown();
- lock.readLockInterruptibly();
- }});
- running.await();
- waitForThreadToEnterWaitState(t, 100);
- t.interrupt();
- awaitTermination(t);
- releaseWriteLock(lock, s);
+ lock.asReadLock().lockInterruptibly();
+ assertTrue(lock.isReadLocked());
+ lock.asReadLock().unlock();
}
/**
@@ -670,54 +723,39 @@
}
/**
- * tryOptimisticRead succeeds and validates if unlocked, fails if locked
+ * tryOptimisticRead succeeds and validates if unlocked, fails if
+ * exclusively locked
*/
public void testValidateOptimistic() throws InterruptedException {
StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.writeLock()) != 0L);
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(p));
- lock.unlockRead(s);
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockRead(s);
- assertTrue(lock.validate(p));
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
- assertTrue(lock.validate(s));
- lock.unlockWrite(s);
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- lock.unlockRead(s);
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
+
+ assertValid(lock, lock.tryOptimisticRead());
+
+ for (Function<StampedLock, Long> writeLocker : writeLockers()) {
+ long s = assertValid(lock, writeLocker.apply(lock));
+ assertEquals(0L, lock.tryOptimisticRead());
+ releaseWriteLock(lock, s);
+ }
+
+ for (Function<StampedLock, Long> readLocker : readLockers()) {
+ long s = assertValid(lock, readLocker.apply(lock));
+ long p = assertValid(lock, lock.tryOptimisticRead());
+ releaseReadLock(lock, s);
+ assertTrue(lock.validate(p));
+ }
+
+ assertValid(lock, lock.tryOptimisticRead());
}
/**
* tryOptimisticRead stamp does not validate if a write lock intervenes
*/
public void testValidateOptimisticWriteLocked() {
- StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
- assertTrue((s = lock.writeLock()) != 0L);
+ final StampedLock lock = new StampedLock();
+ final long p = assertValid(lock, lock.tryOptimisticRead());
+ final long s = assertValid(lock, lock.writeLock());
assertFalse(lock.validate(p));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
+ assertEquals(0L, lock.tryOptimisticRead());
assertTrue(lock.validate(s));
lock.unlockWrite(s);
}
@@ -730,8 +768,8 @@
throws InterruptedException {
final CountDownLatch running = new CountDownLatch(1);
final StampedLock lock = new StampedLock();
- long s, p;
- assertTrue((p = lock.tryOptimisticRead()) != 0L);
+ final long p = assertValid(lock, lock.tryOptimisticRead());
+
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
public void realRun() throws InterruptedException {
lock.writeLockInterruptibly();
@@ -741,228 +779,209 @@
running.await();
assertFalse(lock.validate(p));
- assertFalse((p = lock.tryOptimisticRead()) != 0L);
+ assertEquals(0L, lock.tryOptimisticRead());
t.interrupt();
awaitTermination(t);
}
/**
- * tryConvertToOptimisticRead succeeds and validates if successfully locked,
+ * tryConvertToOptimisticRead succeeds and validates if successfully locked
*/
public void testTryConvertToOptimisticRead() throws InterruptedException {
StampedLock lock = new StampedLock();
- long s, p;
+ long s, p, q;
assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
+ s = assertValid(lock, lock.tryOptimisticRead());
assertEquals(s, lock.tryConvertToOptimisticRead(s));
assertTrue(lock.validate(s));
- assertTrue((p = lock.readLock()) != 0L);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- assertEquals(s, lock.tryConvertToOptimisticRead(s));
- assertTrue(lock.validate(s));
- lock.unlockRead(p);
-
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
-
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
+ for (Function<StampedLock, Long> writeLocker : writeLockers()) {
+ s = assertValid(lock, writeLocker.apply(lock));
+ p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
+ assertFalse(lock.validate(s));
+ assertTrue(lock.validate(p));
+ assertUnlocked(lock);
+ }
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
-
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
-
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
-
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
- assertTrue(lock.validate(p));
+ for (Function<StampedLock, Long> readLocker : readLockers()) {
+ s = assertValid(lock, readLocker.apply(lock));
+ q = assertValid(lock, lock.tryOptimisticRead());
+ assertEquals(q, lock.tryConvertToOptimisticRead(q));
+ assertTrue(lock.validate(q));
+ assertTrue(lock.isReadLocked());
+ p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
+ assertTrue(lock.validate(p));
+ assertTrue(lock.validate(s));
+ assertUnlocked(lock);
+ assertEquals(q, lock.tryConvertToOptimisticRead(q));
+ assertTrue(lock.validate(q));
+ }
}
/**
- * tryConvertToReadLock succeeds and validates if successfully locked
- * or lock free;
+ * tryConvertToReadLock succeeds for valid stamps
*/
public void testTryConvertToReadLock() throws InterruptedException {
StampedLock lock = new StampedLock();
long s, p;
- assertFalse((p = lock.tryConvertToReadLock(0L)) != 0L);
+ assertEquals(0L, lock.tryConvertToReadLock(0L));
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
+ s = assertValid(lock, lock.tryOptimisticRead());
+ p = assertValid(lock, lock.tryConvertToReadLock(s));
assertTrue(lock.isReadLocked());
assertEquals(1, lock.getReadLockCount());
+ assertTrue(lock.validate(s));
lock.unlockRead(p);
- assertTrue((s = lock.tryOptimisticRead()) != 0L);
+ s = assertValid(lock, lock.tryOptimisticRead());
lock.readLock();
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
+ p = assertValid(lock, lock.tryConvertToReadLock(s));
assertTrue(lock.isReadLocked());
assertEquals(2, lock.getReadLockCount());
lock.unlockRead(p);
lock.unlockRead(p);
-
- assertTrue((s = lock.writeLock()) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isReadLocked());
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(p);
-
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertEquals(s, lock.tryConvertToReadLock(s));
- assertTrue(lock.validate(s));
- assertTrue(lock.isReadLocked());
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(s);
-
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(p);
+ assertUnlocked(lock);
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertEquals(s, lock.tryConvertToReadLock(s));
- assertTrue(lock.validate(s));
- assertTrue(lock.isReadLocked());
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(s);
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ for (Function<StampedLock, Long> writeLocker : writeLockers()) {
+ s = assertValid(lock, writeLocker.apply(lock));
+ p = assertValid(lock, lock.tryConvertToReadLock(s));
+ assertFalse(lock.validate(s));
+ assertTrue(lock.isReadLocked());
+ assertEquals(1, lock.getReadLockCount());
+ readUnlocker.accept(lock, p);
+ }
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isReadLocked());
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(p);
-
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertEquals(s, lock.tryConvertToReadLock(s));
- assertTrue(lock.validate(s));
- assertTrue(lock.isReadLocked());
- assertEquals(1, lock.getReadLockCount());
- lock.unlockRead(s);
+ for (Function<StampedLock, Long> readLocker : readLockers()) {
+ s = assertValid(lock, readLocker.apply(lock));
+ assertEquals(s, lock.tryConvertToReadLock(s));
+ assertTrue(lock.validate(s));
+ assertTrue(lock.isReadLocked());
+ assertEquals(1, lock.getReadLockCount());
+ readUnlocker.accept(lock, s);
+ }
+ }
}
/**
- * tryConvertToWriteLock succeeds and validates if successfully locked
- * or lock free;
+ * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
*/
public void testTryConvertToWriteLock() throws InterruptedException {
StampedLock lock = new StampedLock();
long s, p;
- assertFalse((p = lock.tryConvertToWriteLock(0L)) != 0L);
+ assertEquals(0L, lock.tryConvertToWriteLock(0L));
assertTrue((s = lock.tryOptimisticRead()) != 0L);
assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
assertTrue(lock.isWriteLocked());
lock.unlockWrite(p);
- assertTrue((s = lock.writeLock()) != 0L);
- assertEquals(s, lock.tryConvertToWriteLock(s));
- assertTrue(lock.validate(s));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
-
- assertTrue((s = lock.readLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(p);
-
- assertTrue((s = lock.tryWriteLock()) != 0L);
- assertTrue(lock.validate(s));
- assertEquals(s, lock.tryConvertToWriteLock(s));
- assertTrue(lock.validate(s));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(s);
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ for (Function<StampedLock, Long> writeLocker : writeLockers()) {
+ s = assertValid(lock, writeLocker.apply(lock));
+ assertEquals(s, lock.tryConvertToWriteLock(s));
+ assertTrue(lock.validate(s));
+ assertTrue(lock.isWriteLocked());
+ writeUnlocker.accept(lock, s);
+ }
- assertTrue((s = lock.tryReadLock()) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(p);
+ for (Function<StampedLock, Long> readLocker : readLockers()) {
+ s = assertValid(lock, readLocker.apply(lock));
+ p = assertValid(lock, lock.tryConvertToWriteLock(s));
+ assertFalse(lock.validate(s));
+ assertTrue(lock.validate(p));
+ assertTrue(lock.isWriteLocked());
+ writeUnlocker.accept(lock, p);
+ }
+ }
- assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(p);
-
- assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
- assertTrue(lock.validate(s));
- assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
- assertTrue(lock.validate(p));
- assertTrue(lock.isWriteLocked());
- lock.unlockWrite(p);
+ // failure if multiply read locked
+ for (Function<StampedLock, Long> readLocker : readLockers()) {
+ s = assertValid(lock, readLocker.apply(lock));
+ p = assertValid(lock, readLocker.apply(lock));
+ assertEquals(0L, lock.tryConvertToWriteLock(s));
+ assertTrue(lock.validate(s));
+ assertTrue(lock.validate(p));
+ assertEquals(2, lock.getReadLockCount());
+ lock.unlock(p);
+ lock.unlock(s);
+ assertUnlocked(lock);
+ }
}
/**
* asWriteLock can be locked and unlocked
*/
- public void testAsWriteLock() {
+ public void testAsWriteLock() throws Throwable {
StampedLock sl = new StampedLock();
Lock lock = sl.asWriteLock();
- lock.lock();
- assertFalse(lock.tryLock());
- lock.unlock();
- assertTrue(lock.tryLock());
+ for (Action locker : lockLockers(lock)) {
+ locker.run();
+ assertTrue(sl.isWriteLocked());
+ assertFalse(sl.isReadLocked());
+ assertFalse(lock.tryLock());
+ lock.unlock();
+ assertUnlocked(sl);
+ }
}
/**
* asReadLock can be locked and unlocked
*/
- public void testAsReadLock() {
+ public void testAsReadLock() throws Throwable {
StampedLock sl = new StampedLock();
Lock lock = sl.asReadLock();
- lock.lock();
- lock.unlock();
- assertTrue(lock.tryLock());
+ for (Action locker : lockLockers(lock)) {
+ locker.run();
+ assertTrue(sl.isReadLocked());
+ assertFalse(sl.isWriteLocked());
+ assertEquals(1, sl.getReadLockCount());
+ locker.run();
+ assertTrue(sl.isReadLocked());
+ assertEquals(2, sl.getReadLockCount());
+ lock.unlock();
+ lock.unlock();
+ assertUnlocked(sl);
+ }
}
/**
* asReadWriteLock.writeLock can be locked and unlocked
*/
- public void testAsReadWriteLockWriteLock() {
+ public void testAsReadWriteLockWriteLock() throws Throwable {
StampedLock sl = new StampedLock();
Lock lock = sl.asReadWriteLock().writeLock();
- lock.lock();
- assertFalse(lock.tryLock());
- lock.unlock();
- assertTrue(lock.tryLock());
+ for (Action locker : lockLockers(lock)) {
+ locker.run();
+ assertTrue(sl.isWriteLocked());
+ assertFalse(sl.isReadLocked());
+ assertFalse(lock.tryLock());
+ lock.unlock();
+ assertUnlocked(sl);
+ }
}
/**
* asReadWriteLock.readLock can be locked and unlocked
*/
- public void testAsReadWriteLockReadLock() {
+ public void testAsReadWriteLockReadLock() throws Throwable {
StampedLock sl = new StampedLock();
Lock lock = sl.asReadWriteLock().readLock();
- lock.lock();
- lock.unlock();
- assertTrue(lock.tryLock());
+ for (Action locker : lockLockers(lock)) {
+ locker.run();
+ assertTrue(sl.isReadLocked());
+ assertFalse(sl.isWriteLocked());
+ assertEquals(1, sl.getReadLockCount());
+ locker.run();
+ assertTrue(sl.isReadLocked());
+ assertEquals(2, sl.getReadLockCount());
+ lock.unlock();
+ lock.unlock();
+ assertUnlocked(sl);
+ }
}
/**
@@ -985,8 +1004,7 @@
Runnable[] actions = {
() -> {
StampedLock sl = new StampedLock();
- long stamp = sl.tryOptimisticRead();
- assertTrue(stamp != 0);
+ long stamp = assertValid(sl, sl.tryOptimisticRead());
sl.unlockRead(stamp);
},
() -> {
@@ -1003,21 +1021,21 @@
},
() -> {
StampedLock sl = new StampedLock();
- long stamp = sl.tryOptimisticRead();
sl.readLock();
+ long stamp = assertValid(sl, sl.tryOptimisticRead());
sl.unlockRead(stamp);
},
() -> {
StampedLock sl = new StampedLock();
- long stamp = sl.tryOptimisticRead();
sl.readLock();
+ long stamp = assertValid(sl, sl.tryOptimisticRead());
sl.unlock(stamp);
},
() -> {
StampedLock sl = new StampedLock();
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
- assertTrue(stamp != 0);
+ assertValid(sl, stamp);
sl.writeLock();
sl.unlockWrite(stamp);
},
@@ -1043,7 +1061,7 @@
() -> {
StampedLock sl = new StampedLock();
long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
- assertTrue(stamp != 0);
+ assertValid(sl, stamp);
sl.writeLock();
sl.unlockWrite(stamp);
},
@@ -1063,7 +1081,7 @@
StampedLock sl = new StampedLock();
sl.readLock();
long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
- assertTrue(stamp != 0);
+ assertValid(sl, stamp);
sl.readLock();
sl.unlockRead(stamp);
},
@@ -1106,100 +1124,84 @@
}
/**
- * Invalid write stamps result in IllegalMonitorStateException
+ * Invalid stamps result in IllegalMonitorStateException
*/
- public void testInvalidWriteStampsThrowIllegalMonitorStateException() {
- List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
- writeLockers.add((sl) -> sl.writeLock());
- writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
- writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
- writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
+ public void testInvalidStampsThrowIllegalMonitorStateException() {
+ final StampedLock sl = new StampedLock();
+
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlockWrite(0L),
+ () -> sl.unlockRead(0L),
+ () -> sl.unlock(0L));
- List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
- writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
- writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
- writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
- writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+ final long optimisticStamp = sl.tryOptimisticRead();
+ final long readStamp = sl.readLock();
+ sl.unlockRead(readStamp);
+ final long writeStamp = sl.writeLock();
+ sl.unlockWrite(writeStamp);
+ assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
+ final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
+ final Runnable assertNoLongerValidStampsThrow = () -> {
+ for (long noLongerValidStamp : noLongerValidStamps)
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlockWrite(noLongerValidStamp),
+ () -> sl.unlockRead(noLongerValidStamp),
+ () -> sl.unlock(noLongerValidStamp));
+ };
+ assertNoLongerValidStampsThrow.run();
- List<Consumer<StampedLock>> mutaters = new ArrayList<>();
- mutaters.add((sl) -> {});
- mutaters.add((sl) -> sl.readLock());
- for (Function<StampedLock, Long> writeLocker : writeLockers)
- mutaters.add((sl) -> writeLocker.apply(sl));
+ for (Function<StampedLock, Long> readLocker : readLockers())
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
+ final long stamp = readLocker.apply(sl);
+ assertValid(sl, stamp);
+ assertNoLongerValidStampsThrow.run();
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlockWrite(stamp),
+ () -> sl.unlockRead(sl.tryOptimisticRead()),
+ () -> sl.unlockRead(0L));
+ readUnlocker.accept(sl, stamp);
+ assertUnlocked(sl);
+ assertNoLongerValidStampsThrow.run();
+ }
- for (Function<StampedLock, Long> writeLocker : writeLockers)
- for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers)
- for (Consumer<StampedLock> mutater : mutaters) {
- final StampedLock sl = new StampedLock();
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
final long stamp = writeLocker.apply(sl);
- assertTrue(stamp != 0L);
+ assertValid(sl, stamp);
+ assertNoLongerValidStampsThrow.run();
assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlockRead(stamp));
+ () -> sl.unlockRead(stamp),
+ () -> sl.unlockWrite(0L));
writeUnlocker.accept(sl, stamp);
- mutater.accept(sl);
- assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlock(stamp),
- () -> sl.unlockRead(stamp),
- () -> sl.unlockWrite(stamp));
+ assertUnlocked(sl);
+ assertNoLongerValidStampsThrow.run();
}
}
/**
- * Invalid read stamps result in IllegalMonitorStateException
+ * Read locks can be very deeply nested
*/
- public void testInvalidReadStampsThrowIllegalMonitorStateException() {
- List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
- readLockers.add((sl) -> sl.readLock());
- readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
- readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
- readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0, DAYS));
-
- List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
- readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
- readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
- readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
- readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
-
- List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
- writeLockers.add((sl) -> sl.writeLock());
- writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
- writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
- writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
-
- List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
- writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
- writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
- writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
- writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
-
-
- for (Function<StampedLock, Long> readLocker : readLockers)
- for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers)
- for (Function<StampedLock, Long> writeLocker : writeLockers)
- for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers) {
- final StampedLock sl = new StampedLock();
- final long stamp = readLocker.apply(sl);
- assertTrue(stamp != 0L);
- assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlockWrite(stamp));
- readUnlocker.accept(sl, stamp);
- assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlock(stamp),
- () -> sl.unlockRead(stamp),
- () -> sl.unlockWrite(stamp));
- final long writeStamp = writeLocker.apply(sl);
- assertTrue(writeStamp != 0L);
- assertTrue(writeStamp != stamp);
- assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlock(stamp),
- () -> sl.unlockRead(stamp),
- () -> sl.unlockWrite(stamp));
- writeUnlocker.accept(sl, writeStamp);
- assertThrows(IllegalMonitorStateException.class,
- () -> sl.unlock(stamp),
- () -> sl.unlockRead(stamp),
- () -> sl.unlockWrite(stamp));
+ public void testDeeplyNestedReadLocks() {
+ final StampedLock lock = new StampedLock();
+ final int depth = 300;
+ final long[] stamps = new long[depth];
+ final List<Function<StampedLock, Long>> readLockers = readLockers();
+ final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
+ for (int i = 0; i < depth; i++) {
+ Function<StampedLock, Long> readLocker
+ = readLockers.get(i % readLockers.size());
+ long stamp = readLocker.apply(lock);
+ assertEquals(i + 1, lock.getReadLockCount());
+ assertTrue(lock.isReadLocked());
+ stamps[i] = stamp;
}
+ for (int i = 0; i < depth; i++) {
+ BiConsumer<StampedLock, Long> readUnlocker
+ = readUnlockers.get(i % readUnlockers.size());
+ assertEquals(depth - i, lock.getReadLockCount());
+ assertTrue(lock.isReadLocked());
+ readUnlocker.accept(lock, stamps[depth - 1 - i]);
+ }
+ assertUnlocked(lock);
}
-
}