ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
(Generate patch)

Comparing jsr166/src/test/tck/StampedLockTest.java (file contents):
Revision 1.5 by dl, Thu Mar 21 16:26:43 2013 UTC vs.
Revision 1.30 by jsr166, Sat Feb 18 00:32:30 2017 UTC

# Line 5 | Line 5
5   * http://creativecommons.org/publicdomain/zero/1.0/
6   */
7  
8 < import junit.framework.*;
9 < import java.util.concurrent.atomic.AtomicBoolean;
8 > import static java.util.concurrent.TimeUnit.DAYS;
9 > import static java.util.concurrent.TimeUnit.MILLISECONDS;
10 > import static java.util.concurrent.TimeUnit.SECONDS;
11 >
12 > import java.util.ArrayList;
13 > import java.util.List;
14 > import java.util.concurrent.CountDownLatch;
15 > import java.util.concurrent.Future;
16 > import java.util.concurrent.TimeUnit;
17   import java.util.concurrent.locks.Lock;
18   import java.util.concurrent.locks.StampedLock;
19 < import java.util.concurrent.CountDownLatch;
20 < import static java.util.concurrent.TimeUnit.MILLISECONDS;
21 < import java.util.*;
22 < import java.util.concurrent.*;
19 > import java.util.function.BiConsumer;
20 > import java.util.function.Function;
21 >
22 > import junit.framework.Test;
23 > import junit.framework.TestSuite;
24  
25   public class StampedLockTest extends JSR166TestCase {
26      public static void main(String[] args) {
27 <        junit.textui.TestRunner.run(suite());
27 >        main(suite(), args);
28      }
29      public static Test suite() {
30          return new TestSuite(StampedLockTest.class);
31      }
32  
33      /**
26     * A runnable calling writeLockInterruptibly
27     */
28    class InterruptibleLockRunnable extends CheckedRunnable {
29        final StampedLock lock;
30        InterruptibleLockRunnable(StampedLock l) { lock = l; }
31        public void realRun() throws InterruptedException {
32            lock.writeLockInterruptibly();
33        }
34    }
35
36    /**
37     * A runnable calling writeLockInterruptibly that expects to be
38     * interrupted
39     */
40    class InterruptedLockRunnable extends CheckedInterruptedRunnable {
41        final StampedLock lock;
42        InterruptedLockRunnable(StampedLock l) { lock = l; }
43        public void realRun() throws InterruptedException {
44            lock.writeLockInterruptibly();
45        }
46    }
47
48    /**
34       * Releases write lock, checking isWriteLocked before and after
35       */
36 <    void releaseWriteLock(StampedLock lock, long s) {
36 >    void releaseWriteLock(StampedLock lock, long stamp) {
37          assertTrue(lock.isWriteLocked());
38 <        lock.unlockWrite(s);
38 >        assertValid(lock, stamp);
39 >        lock.unlockWrite(stamp);
40          assertFalse(lock.isWriteLocked());
41 +        assertFalse(lock.validate(stamp));
42      }
43  
44      /**
45 <     * Constructed StampedLock is in unlocked state
45 >     * Releases read lock, checking isReadLocked before and after
46       */
47 <    public void testConstructor() {
48 <        StampedLock lock;
49 <        lock = new StampedLock();
50 <        assertFalse(lock.isWriteLocked());
47 >    void releaseReadLock(StampedLock lock, long stamp) {
48 >        assertTrue(lock.isReadLocked());
49 >        assertValid(lock, stamp);
50 >        lock.unlockRead(stamp);
51          assertFalse(lock.isReadLocked());
52 <        assertEquals(lock.getReadLockCount(), 0);
52 >        assertTrue(lock.validate(stamp));
53      }
54  
55 <    /**
56 <     * write-locking and read-locking an unlocked lock succeed
57 <     */
71 <    public void testLock() {
72 <        StampedLock lock = new StampedLock();
73 <        assertFalse(lock.isWriteLocked());
74 <        assertFalse(lock.isReadLocked());
75 <        assertEquals(lock.getReadLockCount(), 0);
76 <        long s = lock.writeLock();
77 <        assertTrue(lock.isWriteLocked());
78 <        assertFalse(lock.isReadLocked());
79 <        assertEquals(lock.getReadLockCount(), 0);
80 <        lock.unlockWrite(s);
81 <        assertFalse(lock.isWriteLocked());
82 <        assertFalse(lock.isReadLocked());
83 <        assertEquals(lock.getReadLockCount(), 0);
84 <        long rs = lock.readLock();
85 <        assertFalse(lock.isWriteLocked());
86 <        assertTrue(lock.isReadLocked());
87 <        assertEquals(lock.getReadLockCount(), 1);
88 <        lock.unlockRead(rs);
89 <        assertFalse(lock.isWriteLocked());
90 <        assertFalse(lock.isReadLocked());
91 <        assertEquals(lock.getReadLockCount(), 0);
55 >    long assertNonZero(long v) {
56 >        assertTrue(v != 0L);
57 >        return v;
58      }
59  
60 <    /**
61 <     * unlock releases either a read or write lock
62 <     */
63 <    public void testUnlock() {
98 <        StampedLock lock = new StampedLock();
99 <        assertFalse(lock.isWriteLocked());
100 <        assertFalse(lock.isReadLocked());
101 <        assertEquals(lock.getReadLockCount(), 0);
102 <        long s = lock.writeLock();
103 <        assertTrue(lock.isWriteLocked());
104 <        assertFalse(lock.isReadLocked());
105 <        assertEquals(lock.getReadLockCount(), 0);
106 <        lock.unlock(s);
107 <        assertFalse(lock.isWriteLocked());
108 <        assertFalse(lock.isReadLocked());
109 <        assertEquals(lock.getReadLockCount(), 0);
110 <        long rs = lock.readLock();
111 <        assertFalse(lock.isWriteLocked());
112 <        assertTrue(lock.isReadLocked());
113 <        assertEquals(lock.getReadLockCount(), 1);
114 <        lock.unlock(rs);
115 <        assertFalse(lock.isWriteLocked());
116 <        assertFalse(lock.isReadLocked());
117 <        assertEquals(lock.getReadLockCount(), 0);
60 >    long assertValid(StampedLock lock, long stamp) {
61 >        assertTrue(stamp != 0L);
62 >        assertTrue(lock.validate(stamp));
63 >        return stamp;
64      }
65  
66 <    /**
121 <     * tryUnlockRead/Write succeeds if locked in associated mode else
122 <     * returns false
123 <     */
124 <    public void testTryUnlock() {
125 <        StampedLock lock = new StampedLock();
126 <        assertFalse(lock.isWriteLocked());
127 <        assertFalse(lock.isReadLocked());
128 <        assertEquals(lock.getReadLockCount(), 0);
129 <        long s = lock.writeLock();
130 <        assertTrue(lock.isWriteLocked());
66 >    void assertUnlocked(StampedLock lock) {
67          assertFalse(lock.isReadLocked());
132        assertEquals(lock.getReadLockCount(), 0);
133        assertFalse(lock.tryUnlockRead());
134        assertTrue(lock.tryUnlockWrite());
135        assertFalse(lock.tryUnlockWrite());
136        assertFalse(lock.tryUnlockRead());
68          assertFalse(lock.isWriteLocked());
69 <        assertFalse(lock.isReadLocked());
70 <        assertEquals(lock.getReadLockCount(), 0);
140 <        long rs = lock.readLock();
141 <        assertFalse(lock.isWriteLocked());
142 <        assertTrue(lock.isReadLocked());
143 <        assertEquals(lock.getReadLockCount(), 1);
144 <        assertFalse(lock.tryUnlockWrite());
145 <        assertTrue(lock.tryUnlockRead());
146 <        assertFalse(lock.tryUnlockRead());
147 <        assertFalse(lock.tryUnlockWrite());
148 <        assertFalse(lock.isWriteLocked());
149 <        assertFalse(lock.isReadLocked());
150 <        assertEquals(lock.getReadLockCount(), 0);
69 >        assertEquals(0, lock.getReadLockCount());
70 >        assertValid(lock, lock.tryOptimisticRead());
71      }
72  
73 <    /**
74 <     * write-unlocking an unlocked lock throws IllegalMonitorStateException
75 <     */
76 <    public void testWriteUnlock_IMSE() {
77 <        StampedLock lock = new StampedLock();
78 <        try {
79 <            lock.unlockWrite(0L);
80 <            shouldThrow();
81 <        } catch (IllegalMonitorStateException success) {}
73 >    List<Action> lockLockers(Lock lock) {
74 >        List<Action> lockers = new ArrayList<>();
75 >        lockers.add(() -> lock.lock());
76 >        lockers.add(() -> lock.lockInterruptibly());
77 >        lockers.add(() -> lock.tryLock());
78 >        lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS));
79 >        lockers.add(() -> lock.tryLock(0L, DAYS));
80 >        lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS));
81 >        return lockers;
82 >    }
83 >
84 >    List<Function<StampedLock, Long>> readLockers() {
85 >        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
86 >        readLockers.add(sl -> sl.readLock());
87 >        readLockers.add(sl -> sl.tryReadLock());
88 >        readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
89 >        readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
90 >        readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
91 >        readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
92 >        return readLockers;
93 >    }
94 >
95 >    List<BiConsumer<StampedLock, Long>> readUnlockers() {
96 >        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
97 >        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
98 >        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
99 >        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
100 >        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
101 >        readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
102 >        return readUnlockers;
103 >    }
104 >
105 >    List<Function<StampedLock, Long>> writeLockers() {
106 >        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
107 >        writeLockers.add(sl -> sl.writeLock());
108 >        writeLockers.add(sl -> sl.tryWriteLock());
109 >        writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
110 >        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
111 >        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
112 >        writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
113 >        return writeLockers;
114 >    }
115 >
116 >    List<BiConsumer<StampedLock, Long>> writeUnlockers() {
117 >        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
118 >        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
119 >        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
120 >        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
121 >        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
122 >        writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
123 >        return writeUnlockers;
124      }
125  
126      /**
127 <     * write-unlocking an unlocked lock throws IllegalMonitorStateException
127 >     * Constructed StampedLock is in unlocked state
128       */
129 <    public void testWriteUnlock_IMSE2() {
130 <        StampedLock lock = new StampedLock();
169 <        try {
170 <            long s = lock.writeLock();
171 <            lock.unlockWrite(s);
172 <            lock.unlockWrite(s);
173 <            shouldThrow();
174 <        } catch (IllegalMonitorStateException success) {}
129 >    public void testConstructor() {
130 >        assertUnlocked(new StampedLock());
131      }
132  
133      /**
134 <     * write-unlocking after readlock throws IllegalMonitorStateException
134 >     * write-locking, then unlocking, an unlocked lock succeed
135       */
136 <    public void testWriteUnlock_IMSE3() {
136 >    public void testWriteLock_lockUnlock() {
137          StampedLock lock = new StampedLock();
138 <        try {
139 <            long s = lock.readLock();
140 <            lock.unlockWrite(s);
141 <            shouldThrow();
142 <        } catch (IllegalMonitorStateException success) {}
138 >
139 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
140 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
141 >            assertFalse(lock.isWriteLocked());
142 >            assertFalse(lock.isReadLocked());
143 >            assertEquals(0, lock.getReadLockCount());
144 >
145 >            long s = writeLocker.apply(lock);
146 >            assertValid(lock, s);
147 >            assertTrue(lock.isWriteLocked());
148 >            assertFalse(lock.isReadLocked());
149 >            assertEquals(0, lock.getReadLockCount());
150 >            writeUnlocker.accept(lock, s);
151 >            assertUnlocked(lock);
152 >        }
153      }
154  
155      /**
156 <     * read-unlocking an unlocked lock throws IllegalMonitorStateException
156 >     * read-locking, then unlocking, an unlocked lock succeed
157       */
158 <    public void testReadUnlock_IMSE() {
158 >    public void testReadLock_lockUnlock() {
159          StampedLock lock = new StampedLock();
160 <        try {
161 <            long s = lock.readLock();
162 <            lock.unlockRead(s);
163 <            lock.unlockRead(s);
164 <            shouldThrow();
165 <        } catch (IllegalMonitorStateException success) {}
160 >
161 >        for (Function<StampedLock, Long> readLocker : readLockers())
162 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
163 >            long s = 42;
164 >            for (int i = 0; i < 2; i++) {
165 >                s = assertValid(lock, readLocker.apply(lock));
166 >                assertFalse(lock.isWriteLocked());
167 >                assertTrue(lock.isReadLocked());
168 >                assertEquals(i + 1, lock.getReadLockCount());
169 >            }
170 >            for (int i = 0; i < 2; i++) {
171 >                assertFalse(lock.isWriteLocked());
172 >                assertTrue(lock.isReadLocked());
173 >                assertEquals(2 - i, lock.getReadLockCount());
174 >                readUnlocker.accept(lock, s);
175 >            }
176 >            assertUnlocked(lock);
177 >        }
178      }
179  
180      /**
181 <     * read-unlocking an unlocked lock throws IllegalMonitorStateException
181 >     * tryUnlockWrite fails if not write locked
182       */
183 <    public void testReadUnlock_IMSE2() {
183 >    public void testTryUnlockWrite_failure() {
184          StampedLock lock = new StampedLock();
185 <        try {
186 <            lock.unlockRead(0L);
187 <            shouldThrow();
188 <        } catch (IllegalMonitorStateException success) {}
185 >        assertFalse(lock.tryUnlockWrite());
186 >
187 >        for (Function<StampedLock, Long> readLocker : readLockers())
188 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
189 >            long s = assertValid(lock, readLocker.apply(lock));
190 >            assertFalse(lock.tryUnlockWrite());
191 >            assertTrue(lock.isReadLocked());
192 >            readUnlocker.accept(lock, s);
193 >            assertUnlocked(lock);
194 >        }
195      }
196  
197      /**
198 <     * read-unlocking after writeLock throws IllegalMonitorStateException
198 >     * tryUnlockRead fails if not read locked
199       */
200 <    public void testReadUnlock_IMSE3() {
200 >    public void testTryUnlockRead_failure() {
201          StampedLock lock = new StampedLock();
202 <        try {
203 <            long s = lock.writeLock();
204 <            lock.unlockRead(s);
205 <            shouldThrow();
206 <        } catch (IllegalMonitorStateException success) {}
202 >        assertFalse(lock.tryUnlockRead());
203 >
204 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
205 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
206 >            long s = writeLocker.apply(lock);
207 >            assertFalse(lock.tryUnlockRead());
208 >            assertTrue(lock.isWriteLocked());
209 >            writeUnlocker.accept(lock, s);
210 >            assertUnlocked(lock);
211 >        }
212      }
213  
214      /**
215 <     * validate(0) fails
215 >     * validate(0L) fails
216       */
217      public void testValidate0() {
218          StampedLock lock = new StampedLock();
# Line 231 | Line 220 | public class StampedLockTest extends JSR
220      }
221  
222      /**
223 <     * A stamp obtained from a successful lock operation validates
223 >     * A stamp obtained from a successful lock operation validates while the lock is held
224       */
225 <    public void testValidate() {
226 <        try {
227 <            StampedLock lock = new StampedLock();
228 <            long s = lock.writeLock();
229 <            assertTrue(lock.validate(s));
230 <            lock.unlockWrite(s);
242 <            s = lock.readLock();
243 <            assertTrue(lock.validate(s));
244 <            lock.unlockRead(s);
245 <            assertTrue((s = lock.tryWriteLock()) != 0L);
246 <            assertTrue(lock.validate(s));
247 <            lock.unlockWrite(s);
248 <            assertTrue((s = lock.tryReadLock()) != 0L);
249 <            assertTrue(lock.validate(s));
250 <            lock.unlockRead(s);
251 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
225 >    public void testValidate() throws InterruptedException {
226 >        StampedLock lock = new StampedLock();
227 >
228 >        for (Function<StampedLock, Long> readLocker : readLockers())
229 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
230 >            long s = assertNonZero(readLocker.apply(lock));
231              assertTrue(lock.validate(s));
232 <            lock.unlockWrite(s);
233 <            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
232 >            readUnlocker.accept(lock, s);
233 >        }
234 >
235 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
236 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
237 >            long s = assertNonZero(writeLocker.apply(lock));
238              assertTrue(lock.validate(s));
239 <            lock.unlockRead(s);
257 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
258 <        } catch (InterruptedException ie) {
259 <            threadUnexpectedException(ie);
239 >            writeUnlocker.accept(lock, s);
240          }
241      }
242  
243      /**
244       * A stamp obtained from an unsuccessful lock operation does not validate
245       */
246 <    public void testValidate2() {
247 <        try {
248 <            StampedLock lock = new StampedLock();
249 <            long s;
250 <            assertTrue((s = lock.writeLock()) != 0L);
251 <            assertTrue(lock.validate(s));
252 <            assertFalse(lock.validate(lock.tryWriteLock()));
253 <            assertFalse(lock.validate(lock.tryWriteLock(100L, MILLISECONDS)));
254 <            assertFalse(lock.validate(lock.tryReadLock()));
255 <            assertFalse(lock.validate(lock.tryReadLock(100L, MILLISECONDS)));
256 <            assertFalse(lock.validate(lock.tryOptimisticRead()));
257 <            lock.unlockWrite(s);
258 <        } catch (InterruptedException ie) {
259 <            threadUnexpectedException(ie);
246 >    public void testValidate2() throws InterruptedException {
247 >        StampedLock lock = new StampedLock();
248 >        long s = assertNonZero(lock.writeLock());
249 >        assertTrue(lock.validate(s));
250 >        assertFalse(lock.validate(lock.tryWriteLock()));
251 >        assertFalse(lock.validate(lock.tryWriteLock(0L, SECONDS)));
252 >        assertFalse(lock.validate(lock.tryReadLock()));
253 >        assertFalse(lock.validate(lock.tryReadLock(0L, SECONDS)));
254 >        assertFalse(lock.validate(lock.tryOptimisticRead()));
255 >        lock.unlockWrite(s);
256 >    }
257 >
258 >    void assertThrowInterruptedExceptionWhenPreInterrupted(Action[] actions) {
259 >        for (Action action : actions) {
260 >            Thread.currentThread().interrupt();
261 >            try {
262 >                action.run();
263 >                shouldThrow();
264 >            }
265 >            catch (InterruptedException success) {}
266 >            catch (Throwable fail) { threadUnexpectedException(fail); }
267 >            assertFalse(Thread.interrupted());
268          }
269      }
270  
271      /**
272 <     * writeLockInterruptibly is interruptible
272 >     * interruptible operations throw InterruptedException when pre-interrupted
273       */
274 <    public void testWriteLockInterruptibly_Interruptible() {
287 <        final CountDownLatch running = new CountDownLatch(1);
274 >    public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() {
275          final StampedLock lock = new StampedLock();
276 <        long s = lock.writeLock();
277 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
278 <            public void realRun() throws InterruptedException {
279 <                running.countDown();
280 <                lock.writeLockInterruptibly();
281 <            }});
282 <        try {
283 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
284 <            t.interrupt();
285 <            awaitTermination(t);
286 <            releaseWriteLock(lock, s);
287 <        } catch (InterruptedException ie) {
288 <            threadUnexpectedException(ie);
276 >
277 >        Action[] interruptibleLockActions = {
278 >            () -> lock.writeLockInterruptibly(),
279 >            () -> lock.tryWriteLock(Long.MIN_VALUE, DAYS),
280 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
281 >            () -> lock.readLockInterruptibly(),
282 >            () -> lock.tryReadLock(Long.MIN_VALUE, DAYS),
283 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
284 >            () -> lock.asWriteLock().lockInterruptibly(),
285 >            () -> lock.asWriteLock().tryLock(0L, DAYS),
286 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
287 >            () -> lock.asReadLock().lockInterruptibly(),
288 >            () -> lock.asReadLock().tryLock(0L, DAYS),
289 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
290 >        };
291 >        shuffle(interruptibleLockActions);
292 >
293 >        assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
294 >        {
295 >            long s = lock.writeLock();
296 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
297 >            lock.unlockWrite(s);
298 >        }
299 >        {
300 >            long s = lock.readLock();
301 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
302 >            lock.unlockRead(s);
303          }
304      }
305  
306 +    void assertThrowInterruptedExceptionWhenInterrupted(Action[] actions) {
307 +        int n = actions.length;
308 +        Future<?>[] futures = new Future<?>[n];
309 +        CountDownLatch threadsStarted = new CountDownLatch(n);
310 +        CountDownLatch done = new CountDownLatch(n);
311 +
312 +        for (int i = 0; i < n; i++) {
313 +            Action action = actions[i];
314 +            futures[i] = cachedThreadPool.submit(new CheckedRunnable() {
315 +                public void realRun() throws Throwable {
316 +                    threadsStarted.countDown();
317 +                    try {
318 +                        action.run();
319 +                        shouldThrow();
320 +                    }
321 +                    catch (InterruptedException success) {}
322 +                    catch (Throwable fail) { threadUnexpectedException(fail); }
323 +                    assertFalse(Thread.interrupted());
324 +                    done.countDown();
325 +                }});
326 +        }
327 +
328 +        await(threadsStarted);
329 +        assertEquals(n, done.getCount());
330 +        for (Future<?> future : futures) // Interrupt all the tasks
331 +            future.cancel(true);
332 +        await(done);
333 +    }
334 +
335      /**
336 <     * timed tryWriteLock is interruptible
336 >     * interruptible operations throw InterruptedException when write locked and interrupted
337       */
338 <    public void testWriteTryLock_Interruptible() {
309 <        final CountDownLatch running = new CountDownLatch(1);
338 >    public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
339          final StampedLock lock = new StampedLock();
340          long s = lock.writeLock();
341 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
342 <            public void realRun() throws InterruptedException {
343 <                running.countDown();
344 <                lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS);
345 <            }});
346 <        try {
347 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
348 <            t.interrupt();
349 <            awaitTermination(t);
350 <            releaseWriteLock(lock, s);
351 <        } catch (InterruptedException ie) {
352 <            threadUnexpectedException(ie);
353 <        }
341 >
342 >        Action[] interruptibleLockBlockingActions = {
343 >            () -> lock.writeLockInterruptibly(),
344 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
345 >            () -> lock.readLockInterruptibly(),
346 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
347 >            () -> lock.asWriteLock().lockInterruptibly(),
348 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
349 >            () -> lock.asReadLock().lockInterruptibly(),
350 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
351 >        };
352 >        shuffle(interruptibleLockBlockingActions);
353 >
354 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
355      }
356  
357      /**
358 <     * readLockInterruptibly is interruptible
358 >     * interruptible operations throw InterruptedException when read locked and interrupted
359       */
360 <    public void testReadLockInterruptibly_Interruptible() {
331 <        final CountDownLatch running = new CountDownLatch(1);
360 >    public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
361          final StampedLock lock = new StampedLock();
362 <        long s = lock.writeLock();
363 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
364 <            public void realRun() throws InterruptedException {
365 <                running.countDown();
366 <                lock.readLockInterruptibly();
367 <            }});
368 <        try {
369 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
370 <            t.interrupt();
371 <            awaitTermination(t);
372 <            releaseWriteLock(lock, s);
344 <        } catch (InterruptedException ie) {
345 <            threadUnexpectedException(ie);
346 <        }
362 >        long s = lock.readLock();
363 >
364 >        Action[] interruptibleLockBlockingActions = {
365 >            () -> lock.writeLockInterruptibly(),
366 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
367 >            () -> lock.asWriteLock().lockInterruptibly(),
368 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
369 >        };
370 >        shuffle(interruptibleLockBlockingActions);
371 >
372 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
373      }
374  
375      /**
376 <     * timed tryReadLock is interruptible
376 >     * Non-interruptible operations ignore and preserve interrupt status
377       */
378 <    public void testReadTryLock_Interruptible() {
353 <        final CountDownLatch running = new CountDownLatch(1);
378 >    public void testNonInterruptibleOperationsIgnoreInterrupts() {
379          final StampedLock lock = new StampedLock();
380 <        long s = lock.writeLock();
381 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
382 <            public void realRun() throws InterruptedException {
383 <                running.countDown();
384 <                lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS);
385 <            }});
386 <        try {
387 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
388 <            t.interrupt();
389 <            awaitTermination(t);
390 <            releaseWriteLock(lock, s);
391 <        } catch (InterruptedException ie) {
392 <            threadUnexpectedException(ie);
380 >        Thread.currentThread().interrupt();
381 >
382 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
383 >            long s = assertValid(lock, lock.readLock());
384 >            readUnlocker.accept(lock, s);
385 >            s = assertValid(lock, lock.tryReadLock());
386 >            readUnlocker.accept(lock, s);
387 >        }
388 >
389 >        lock.asReadLock().lock();
390 >        lock.asReadLock().unlock();
391 >
392 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
393 >            long s = assertValid(lock, lock.writeLock());
394 >            writeUnlocker.accept(lock, s);
395 >            s = assertValid(lock, lock.tryWriteLock());
396 >            writeUnlocker.accept(lock, s);
397          }
398 +
399 +        lock.asWriteLock().lock();
400 +        lock.asWriteLock().unlock();
401 +
402 +        assertTrue(Thread.interrupted());
403      }
404  
405      /**
406       * tryWriteLock on an unlocked lock succeeds
407       */
408 <    public void testWriteTryLock() {
408 >    public void testTryWriteLock() {
409          final StampedLock lock = new StampedLock();
410          long s = lock.tryWriteLock();
411          assertTrue(s != 0L);
412          assertTrue(lock.isWriteLocked());
413 <        long s2 = lock.tryWriteLock();
380 <        assertEquals(s2, 0L);
413 >        assertEquals(0L, lock.tryWriteLock());
414          releaseWriteLock(lock, s);
415      }
416  
417      /**
418       * tryWriteLock fails if locked
419       */
420 <    public void testWriteTryLockWhenLocked() {
420 >    public void testTryWriteLockWhenLocked() {
421          final StampedLock lock = new StampedLock();
422          long s = lock.writeLock();
423          Thread t = newStartedThread(new CheckedRunnable() {
424              public void realRun() {
425 <                long ws = lock.tryWriteLock();
393 <                assertTrue(ws == 0L);
425 >                assertEquals(0L, lock.tryWriteLock());
426              }});
427  
428 +        assertEquals(0L, lock.tryWriteLock());
429          awaitTermination(t);
430          releaseWriteLock(lock, s);
431      }
# Line 400 | Line 433 | public class StampedLockTest extends JSR
433      /**
434       * tryReadLock fails if write-locked
435       */
436 <    public void testReadTryLockWhenLocked() {
436 >    public void testTryReadLockWhenLocked() {
437          final StampedLock lock = new StampedLock();
438          long s = lock.writeLock();
439          Thread t = newStartedThread(new CheckedRunnable() {
440              public void realRun() {
441 <                long rs = lock.tryReadLock();
409 <                assertEquals(rs, 0L);
441 >                assertEquals(0L, lock.tryReadLock());
442              }});
443  
444 +        assertEquals(0L, lock.tryReadLock());
445          awaitTermination(t);
446          releaseWriteLock(lock, s);
447      }
# Line 422 | Line 455 | public class StampedLockTest extends JSR
455          Thread t = newStartedThread(new CheckedRunnable() {
456              public void realRun() throws InterruptedException {
457                  long s2 = lock.tryReadLock();
458 <                assertTrue(s2 != 0L);
458 >                assertValid(lock, s2);
459                  lock.unlockRead(s2);
460                  long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
461 <                assertTrue(s3 != 0L);
461 >                assertValid(lock, s3);
462                  lock.unlockRead(s3);
463                  long s4 = lock.readLock();
464 +                assertValid(lock, s4);
465                  lock.unlockRead(s4);
466 +                lock.asReadLock().lock();
467 +                lock.asReadLock().unlock();
468 +                lock.asReadLock().lockInterruptibly();
469 +                lock.asReadLock().unlock();
470 +                lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
471 +                lock.asReadLock().unlock();
472              }});
473  
474          awaitTermination(t);
# Line 438 | Line 478 | public class StampedLockTest extends JSR
478      /**
479       * A writelock succeeds only after a reading thread unlocks
480       */
481 <    public void testWriteAfterReadLock() {
481 >    public void testWriteAfterReadLock() throws InterruptedException {
482          final CountDownLatch running = new CountDownLatch(1);
483          final StampedLock lock = new StampedLock();
484          long rs = lock.readLock();
# Line 448 | Line 488 | public class StampedLockTest extends JSR
488                  long s = lock.writeLock();
489                  lock.unlockWrite(s);
490              }});
491 <        try {
492 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
493 <            assertFalse(lock.isWriteLocked());
494 <            lock.unlockRead(rs);
495 <            awaitTermination(t);
496 <            assertFalse(lock.isWriteLocked());
497 <        } catch (InterruptedException ie) {
458 <            threadUnexpectedException(ie);
459 <        }
491 >
492 >        running.await();
493 >        waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS);
494 >        assertFalse(lock.isWriteLocked());
495 >        lock.unlockRead(rs);
496 >        awaitTermination(t);
497 >        assertFalse(lock.isWriteLocked());
498      }
499  
500      /**
# Line 470 | Line 508 | public class StampedLockTest extends JSR
508                  long rs = lock.readLock();
509                  lock.unlockRead(rs);
510              }});
511 +
512          awaitTermination(t1);
513  
514          Thread t2 = newStartedThread(new CheckedRunnable() {
# Line 477 | Line 516 | public class StampedLockTest extends JSR
516                  long ws = lock.writeLock();
517                  lock.unlockWrite(ws);
518              }});
519 +
520 +        assertTrue(lock.isReadLocked());
521          assertFalse(lock.isWriteLocked());
522          lock.unlockRead(s);
523          awaitTermination(t2);
# Line 488 | Line 529 | public class StampedLockTest extends JSR
529       */
530      public void testReadAfterWriteLock() {
531          final StampedLock lock = new StampedLock();
532 +        final CountDownLatch threadsStarted = new CountDownLatch(2);
533          final long s = lock.writeLock();
534          Thread t1 = newStartedThread(new CheckedRunnable() {
535              public void realRun() {
536 +                threadsStarted.countDown();
537                  long rs = lock.readLock();
538                  lock.unlockRead(rs);
539              }});
540          Thread t2 = newStartedThread(new CheckedRunnable() {
541              public void realRun() {
542 +                threadsStarted.countDown();
543                  long rs = lock.readLock();
544                  lock.unlockRead(rs);
545              }});
546  
547 +        await(threadsStarted);
548 +        waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS);
549 +        waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS);
550          releaseWriteLock(lock, s);
551          awaitTermination(t1);
552          awaitTermination(t2);
553      }
554  
555      /**
556 <     * tryReadLock succeeds if readlocked but not writelocked
556 >     * tryReadLock succeeds if read locked but not write locked
557       */
558      public void testTryLockWhenReadLocked() {
559          final StampedLock lock = new StampedLock();
# Line 514 | Line 561 | public class StampedLockTest extends JSR
561          Thread t = newStartedThread(new CheckedRunnable() {
562              public void realRun() {
563                  long rs = lock.tryReadLock();
564 <                threadAssertTrue(rs != 0L);
564 >                assertValid(lock, rs);
565                  lock.unlockRead(rs);
566              }});
567  
# Line 523 | Line 570 | public class StampedLockTest extends JSR
570      }
571  
572      /**
573 <     * tryWriteLock fails when readlocked
573 >     * tryWriteLock fails when read locked
574       */
575 <    public void testWriteTryLockWhenReadLocked() {
575 >    public void testTryWriteLockWhenReadLocked() {
576          final StampedLock lock = new StampedLock();
577          long s = lock.readLock();
578          Thread t = newStartedThread(new CheckedRunnable() {
579              public void realRun() {
580 <                long ws = lock.tryWriteLock();
534 <                threadAssertEquals(ws, 0L);
580 >                threadAssertEquals(0L, lock.tryWriteLock());
581              }});
582  
583          awaitTermination(t);
# Line 539 | Line 585 | public class StampedLockTest extends JSR
585      }
586  
587      /**
588 <     * timed tryWriteLock times out if locked
588 >     * timed lock operations time out if lock not available
589       */
590 <    public void testWriteTryLock_Timeout() {
590 >    public void testTimedLock_Timeout() throws Exception {
591 >        ArrayList<Future<?>> futures = new ArrayList<>();
592 >
593 >        // Write locked
594          final StampedLock lock = new StampedLock();
595 <        long s = lock.writeLock();
596 <        Thread t = newStartedThread(new CheckedRunnable() {
595 >        long stamp = lock.writeLock();
596 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
597 >        assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
598 >        assertFalse(lock.asReadLock().tryLock(0L, DAYS));
599 >        assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
600 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
601 >        assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
602 >        assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
603 >        assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
604 >
605 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
606              public void realRun() throws InterruptedException {
607                  long startTime = System.nanoTime();
608 <                long timeoutMillis = 10;
609 <                long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
610 <                assertEquals(ws, 0L);
553 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
554 <            }});
608 >                assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
609 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
610 >            }}));
611  
612 <        awaitTermination(t);
613 <        releaseWriteLock(lock, s);
614 <    }
612 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
613 >            public void realRun() throws InterruptedException {
614 >                long startTime = System.nanoTime();
615 >                assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
616 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
617 >            }}));
618 >
619 >        // Read locked
620 >        final StampedLock lock2 = new StampedLock();
621 >        long stamp2 = lock2.readLock();
622 >        assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
623 >        assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
624 >        assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
625 >        assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
626  
627 <    /**
561 <     * timed tryReadLock times out if write-locked
562 <     */
563 <    public void testReadTryLock_Timeout() {
564 <        final StampedLock lock = new StampedLock();
565 <        long s = lock.writeLock();
566 <        Thread t = newStartedThread(new CheckedRunnable() {
627 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
628              public void realRun() throws InterruptedException {
629                  long startTime = System.nanoTime();
630 <                long timeoutMillis = 10;
631 <                long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
632 <                assertEquals(rs, 0L);
633 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
634 <            }});
635 <        
636 <        awaitTermination(t);
637 <        assertTrue(lock.isWriteLocked());
638 <        lock.unlockWrite(s);
630 >                assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
631 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
632 >            }}));
633 >
634 >        for (Future<?> future : futures)
635 >            assertNull(future.get());
636 >
637 >        releaseWriteLock(lock, stamp);
638 >        releaseReadLock(lock2, stamp2);
639      }
640  
641      /**
642 <     * writeLockInterruptibly succeeds if unlocked, else is interruptible
642 >     * writeLockInterruptibly succeeds if unlocked
643       */
644 <    public void testWriteLockInterruptibly() {
584 <        final CountDownLatch running = new CountDownLatch(1);
644 >    public void testWriteLockInterruptibly() throws InterruptedException {
645          final StampedLock lock = new StampedLock();
646 <        long s = 0L;
647 <        try {
648 <            s = lock.writeLockInterruptibly();
589 <        } catch (InterruptedException ie) {
590 <            threadUnexpectedException(ie);
591 <        }
592 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
593 <            public void realRun() throws InterruptedException {
594 <                running.countDown();
595 <                lock.writeLockInterruptibly();
596 <            }});
597 <
598 <        try {
599 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
600 <            t.interrupt();
601 <            assertTrue(lock.isWriteLocked());
602 <            awaitTermination(t);
603 <            releaseWriteLock(lock, s);
604 <        } catch (InterruptedException ie) {
605 <            threadUnexpectedException(ie);
606 <        }
607 <
646 >        long s = lock.writeLockInterruptibly();
647 >        assertTrue(lock.isWriteLocked());
648 >        releaseWriteLock(lock, s);
649      }
650  
651      /**
652 <     * readLockInterruptibly succeeds if lock free else is interruptible
652 >     * readLockInterruptibly succeeds if lock free
653       */
654 <    public void testReadLockInterruptibly() {
614 <        final CountDownLatch running = new CountDownLatch(1);
654 >    public void testReadLockInterruptibly() throws InterruptedException {
655          final StampedLock lock = new StampedLock();
656 <        long s = 0L;
657 <        try {
658 <            s = lock.readLockInterruptibly();
659 <            lock.unlockRead(s);
660 <            s = lock.writeLockInterruptibly();
661 <        } catch (InterruptedException ie) {
662 <            threadUnexpectedException(ie);
663 <        }
624 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
625 <            public void realRun() throws InterruptedException {
626 <                running.countDown();
627 <                lock.readLockInterruptibly();
628 <            }});
629 <        try {
630 <            running.await(); Thread.sleep(SHORT_DELAY_MS);
631 <            t.interrupt();
632 <            awaitTermination(t);
633 <            releaseWriteLock(lock, s);
634 <        } catch (InterruptedException ie) {
635 <            threadUnexpectedException(ie);
636 <        }
656 >
657 >        long s = assertValid(lock, lock.readLockInterruptibly());
658 >        assertTrue(lock.isReadLocked());
659 >        lock.unlockRead(s);
660 >
661 >        lock.asReadLock().lockInterruptibly();
662 >        assertTrue(lock.isReadLocked());
663 >        lock.asReadLock().unlock();
664      }
665  
666      /**
# Line 665 | Line 692 | public class StampedLockTest extends JSR
692      }
693  
694      /**
695 <     * tryOptimisticRead succeeds and validates if unlocked, fails if locked
695 >     * tryOptimisticRead succeeds and validates if unlocked, fails if
696 >     * exclusively locked
697       */
698 <    public void testValidateOptimistic() {
699 <        try {
700 <            StampedLock lock = new StampedLock();
701 <            long s, p;
702 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
703 <            assertTrue(lock.validate(p));
704 <            assertTrue((s = lock.writeLock()) != 0L);
705 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
706 <            assertTrue(lock.validate(s));
707 <            lock.unlockWrite(s);
708 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
709 <            assertTrue(lock.validate(p));
710 <            assertTrue((s = lock.readLock()) != 0L);
711 <            assertTrue(lock.validate(s));
712 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
685 <            assertTrue(lock.validate(p));
686 <            lock.unlockRead(s);
687 <            assertTrue((s = lock.tryWriteLock()) != 0L);
688 <            assertTrue(lock.validate(s));
689 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
690 <            lock.unlockWrite(s);
691 <            assertTrue((s = lock.tryReadLock()) != 0L);
692 <            assertTrue(lock.validate(s));
693 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
694 <            lock.unlockRead(s);
698 >    public void testValidateOptimistic() throws InterruptedException {
699 >        StampedLock lock = new StampedLock();
700 >
701 >        assertValid(lock, lock.tryOptimisticRead());
702 >
703 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
704 >            long s = assertValid(lock, writeLocker.apply(lock));
705 >            assertEquals(0L, lock.tryOptimisticRead());
706 >            releaseWriteLock(lock, s);
707 >        }
708 >
709 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
710 >            long s = assertValid(lock, readLocker.apply(lock));
711 >            long p = assertValid(lock, lock.tryOptimisticRead());
712 >            releaseReadLock(lock, s);
713              assertTrue(lock.validate(p));
696            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
697            assertFalse((p = lock.tryOptimisticRead()) != 0L);
698            assertTrue(lock.validate(s));
699            lock.unlockWrite(s);
700            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
701            assertTrue(lock.validate(s));
702            assertTrue((p = lock.tryOptimisticRead()) != 0L);
703            lock.unlockRead(s);
704            assertTrue((p = lock.tryOptimisticRead()) != 0L);
705        } catch (InterruptedException ie) {
706            threadUnexpectedException(ie);
714          }
715 +
716 +        assertValid(lock, lock.tryOptimisticRead());
717      }
718  
719      /**
720       * tryOptimisticRead stamp does not validate if a write lock intervenes
721       */
722      public void testValidateOptimisticWriteLocked() {
723 <        StampedLock lock = new StampedLock();
724 <        long s, p;
725 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
717 <        assertTrue((s = lock.writeLock()) != 0L);
723 >        final StampedLock lock = new StampedLock();
724 >        final long p = assertValid(lock, lock.tryOptimisticRead());
725 >        final long s = assertValid(lock, lock.writeLock());
726          assertFalse(lock.validate(p));
727 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
727 >        assertEquals(0L, lock.tryOptimisticRead());
728          assertTrue(lock.validate(s));
729          lock.unlockWrite(s);
730      }
# Line 725 | Line 733 | public class StampedLockTest extends JSR
733       * tryOptimisticRead stamp does not validate if a write lock
734       * intervenes in another thread
735       */
736 <    public void testValidateOptimisticWriteLocked2() {
736 >    public void testValidateOptimisticWriteLocked2()
737 >            throws InterruptedException {
738          final CountDownLatch running = new CountDownLatch(1);
739          final StampedLock lock = new StampedLock();
740 <        long s, p;
741 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
740 >        final long p = assertValid(lock, lock.tryOptimisticRead());
741 >
742          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
743 <                public void realRun() throws InterruptedException {
744 <                    lock.writeLockInterruptibly();
745 <                    running.countDown();
746 <                    lock.writeLockInterruptibly();
747 <                }});
748 <        try {
749 <            running.await();
750 <            assertFalse(lock.validate(p));
751 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
752 <            t.interrupt();
753 <            awaitTermination(t);
745 <        } catch (InterruptedException ie) {
746 <            threadUnexpectedException(ie);
747 <        }
743 >            public void realRun() throws InterruptedException {
744 >                lock.writeLockInterruptibly();
745 >                running.countDown();
746 >                lock.writeLockInterruptibly();
747 >            }});
748 >
749 >        running.await();
750 >        assertFalse(lock.validate(p));
751 >        assertEquals(0L, lock.tryOptimisticRead());
752 >        t.interrupt();
753 >        awaitTermination(t);
754      }
755  
756      /**
757 <     * tryConvertToOptimisticRead succeeds and validates if successfully locked,
758 <     */
759 <    public void testTryConvertToOptimisticRead() {
760 <        try {
761 <            StampedLock lock = new StampedLock();
762 <            long s, p;
763 <            s = 0L;
764 <            assertFalse((p = lock.tryConvertToOptimisticRead(s)) != 0L);
765 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
766 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
767 <            assertTrue((s = lock.writeLock()) != 0L);
768 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
769 <            assertTrue(lock.validate(p));
770 <            assertTrue((s = lock.readLock()) != 0L);
771 <            assertTrue(lock.validate(s));
766 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
767 <            assertTrue(lock.validate(p));
768 <            assertTrue((s = lock.tryWriteLock()) != 0L);
769 <            assertTrue(lock.validate(s));
770 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
771 <            assertTrue(lock.validate(p));
772 <            assertTrue((s = lock.tryReadLock()) != 0L);
773 <            assertTrue(lock.validate(s));
774 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
757 >     * tryConvertToOptimisticRead succeeds and validates if successfully locked
758 >     */
759 >    public void testTryConvertToOptimisticRead() throws InterruptedException {
760 >        StampedLock lock = new StampedLock();
761 >        long s, p, q;
762 >        assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
763 >
764 >        s = assertValid(lock, lock.tryOptimisticRead());
765 >        assertEquals(s, lock.tryConvertToOptimisticRead(s));
766 >        assertTrue(lock.validate(s));
767 >
768 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
769 >            s = assertValid(lock, writeLocker.apply(lock));
770 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
771 >            assertFalse(lock.validate(s));
772              assertTrue(lock.validate(p));
773 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
774 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
773 >            assertUnlocked(lock);
774 >        }
775 >
776 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
777 >            s = assertValid(lock, readLocker.apply(lock));
778 >            q = assertValid(lock, lock.tryOptimisticRead());
779 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
780 >            assertTrue(lock.validate(q));
781 >            assertTrue(lock.isReadLocked());
782 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
783              assertTrue(lock.validate(p));
779            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
784              assertTrue(lock.validate(s));
785 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
786 <            assertTrue(lock.validate(p));
787 <        } catch (InterruptedException ie) {
784 <            threadUnexpectedException(ie);
785 >            assertUnlocked(lock);
786 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
787 >            assertTrue(lock.validate(q));
788          }
789      }
790  
791      /**
792 <     * tryConvertToReadLock succeeds and validates if successfully locked
790 <     * or lock free;
792 >     * tryConvertToReadLock succeeds for valid stamps
793       */
794 <    public void testTryConvertToReadLock() {
795 <        try {
796 <            StampedLock lock = new StampedLock();
797 <            long s, p;
798 <            s = 0L;
799 <            assertFalse((p = lock.tryConvertToReadLock(s)) != 0L);
800 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
801 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
802 <            lock.unlockRead(p);
803 <            assertTrue((s = lock.writeLock()) != 0L);
804 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
805 <            assertTrue(lock.validate(p));
806 <            lock.unlockRead(p);
807 <            assertTrue((s = lock.readLock()) != 0L);
808 <            assertTrue(lock.validate(s));
809 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
810 <            assertTrue(lock.validate(p));
811 <            lock.unlockRead(p);
812 <            assertTrue((s = lock.tryWriteLock()) != 0L);
813 <            assertTrue(lock.validate(s));
814 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
815 <            assertTrue(lock.validate(p));
816 <            lock.unlockRead(p);
817 <            assertTrue((s = lock.tryReadLock()) != 0L);
818 <            assertTrue(lock.validate(s));
819 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
820 <            assertTrue(lock.validate(p));
821 <            lock.unlockRead(p);
822 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
823 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
824 <            assertTrue(lock.validate(p));
825 <            lock.unlockRead(p);
826 <            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
827 <            assertTrue(lock.validate(s));
828 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
829 <            assertTrue(lock.validate(p));
830 <            lock.unlockRead(p);
831 <        } catch (InterruptedException ie) {
832 <            threadUnexpectedException(ie);
794 >    public void testTryConvertToReadLock() throws InterruptedException {
795 >        StampedLock lock = new StampedLock();
796 >        long s, p;
797 >
798 >        assertEquals(0L, lock.tryConvertToReadLock(0L));
799 >
800 >        s = assertValid(lock, lock.tryOptimisticRead());
801 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
802 >        assertTrue(lock.isReadLocked());
803 >        assertEquals(1, lock.getReadLockCount());
804 >        assertTrue(lock.validate(s));
805 >        lock.unlockRead(p);
806 >
807 >        s = assertValid(lock, lock.tryOptimisticRead());
808 >        lock.readLock();
809 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
810 >        assertTrue(lock.isReadLocked());
811 >        assertEquals(2, lock.getReadLockCount());
812 >        lock.unlockRead(p);
813 >        lock.unlockRead(p);
814 >        assertUnlocked(lock);
815 >
816 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
817 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
818 >                s = assertValid(lock, writeLocker.apply(lock));
819 >                p = assertValid(lock, lock.tryConvertToReadLock(s));
820 >                assertFalse(lock.validate(s));
821 >                assertTrue(lock.isReadLocked());
822 >                assertEquals(1, lock.getReadLockCount());
823 >                readUnlocker.accept(lock, p);
824 >            }
825 >
826 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
827 >                s = assertValid(lock, readLocker.apply(lock));
828 >                assertEquals(s, lock.tryConvertToReadLock(s));
829 >                assertTrue(lock.validate(s));
830 >                assertTrue(lock.isReadLocked());
831 >                assertEquals(1, lock.getReadLockCount());
832 >                readUnlocker.accept(lock, s);
833 >            }
834          }
835      }
836  
837      /**
838 <     * tryConvertToWriteLock succeeds and validates if successfully locked
839 <     * or lock free;
840 <     */
841 <    public void testTryConvertToWriteLock() {
842 <        try {
843 <            StampedLock lock = new StampedLock();
844 <            long s, p;
845 <            s = 0L;
846 <            assertFalse((p = lock.tryConvertToWriteLock(s)) != 0L);
847 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
848 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
849 <            lock.unlockWrite(p);
850 <            assertTrue((s = lock.writeLock()) != 0L);
851 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
852 <            assertTrue(lock.validate(p));
853 <            lock.unlockWrite(p);
854 <            assertTrue((s = lock.readLock()) != 0L);
855 <            assertTrue(lock.validate(s));
856 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
857 <            assertTrue(lock.validate(p));
858 <            lock.unlockWrite(p);
859 <            assertTrue((s = lock.tryWriteLock()) != 0L);
860 <            assertTrue(lock.validate(s));
861 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
862 <            assertTrue(lock.validate(p));
863 <            lock.unlockWrite(p);
864 <            assertTrue((s = lock.tryReadLock()) != 0L);
865 <            assertTrue(lock.validate(s));
866 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
867 <            assertTrue(lock.validate(p));
868 <            lock.unlockWrite(p);
869 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
870 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
871 <            assertTrue(lock.validate(p));
872 <            lock.unlockWrite(p);
873 <            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
838 >     * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
839 >     */
840 >    public void testTryConvertToWriteLock() throws InterruptedException {
841 >        StampedLock lock = new StampedLock();
842 >        long s, p;
843 >
844 >        assertEquals(0L, lock.tryConvertToWriteLock(0L));
845 >
846 >        assertTrue((s = lock.tryOptimisticRead()) != 0L);
847 >        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
848 >        assertTrue(lock.isWriteLocked());
849 >        lock.unlockWrite(p);
850 >
851 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
852 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
853 >                s = assertValid(lock, writeLocker.apply(lock));
854 >                assertEquals(s, lock.tryConvertToWriteLock(s));
855 >                assertTrue(lock.validate(s));
856 >                assertTrue(lock.isWriteLocked());
857 >                writeUnlocker.accept(lock, s);
858 >            }
859 >
860 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
861 >                s = assertValid(lock, readLocker.apply(lock));
862 >                p = assertValid(lock, lock.tryConvertToWriteLock(s));
863 >                assertFalse(lock.validate(s));
864 >                assertTrue(lock.validate(p));
865 >                assertTrue(lock.isWriteLocked());
866 >                writeUnlocker.accept(lock, p);
867 >            }
868 >        }
869 >
870 >        // failure if multiply read locked
871 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
872 >            s = assertValid(lock, readLocker.apply(lock));
873 >            p = assertValid(lock, readLocker.apply(lock));
874 >            assertEquals(0L, lock.tryConvertToWriteLock(s));
875              assertTrue(lock.validate(s));
872            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
876              assertTrue(lock.validate(p));
877 <            lock.unlockWrite(p);
878 <        } catch (InterruptedException ie) {
879 <            threadUnexpectedException(ie);
877 >            assertEquals(2, lock.getReadLockCount());
878 >            lock.unlock(p);
879 >            lock.unlock(s);
880 >            assertUnlocked(lock);
881          }
882      }
883  
884      /**
885       * asWriteLock can be locked and unlocked
886       */
887 <    public void testAsWriteLock() {
887 >    public void testAsWriteLock() throws Throwable {
888          StampedLock sl = new StampedLock();
889          Lock lock = sl.asWriteLock();
890 <        lock.lock();
891 <        assertFalse(lock.tryLock());
892 <        lock.unlock();
893 <        assertTrue(lock.tryLock());
890 >        for (Action locker : lockLockers(lock)) {
891 >            locker.run();
892 >            assertTrue(sl.isWriteLocked());
893 >            assertFalse(sl.isReadLocked());
894 >            assertFalse(lock.tryLock());
895 >            lock.unlock();
896 >            assertUnlocked(sl);
897 >        }
898      }
899  
900      /**
901       * asReadLock can be locked and unlocked
902       */
903 <    public void testAsReadLock() {
903 >    public void testAsReadLock() throws Throwable {
904          StampedLock sl = new StampedLock();
905          Lock lock = sl.asReadLock();
906 <        lock.lock();
907 <        lock.unlock();
908 <        assertTrue(lock.tryLock());
906 >        for (Action locker : lockLockers(lock)) {
907 >            locker.run();
908 >            assertTrue(sl.isReadLocked());
909 >            assertFalse(sl.isWriteLocked());
910 >            assertEquals(1, sl.getReadLockCount());
911 >            locker.run();
912 >            assertTrue(sl.isReadLocked());
913 >            assertEquals(2, sl.getReadLockCount());
914 >            lock.unlock();
915 >            lock.unlock();
916 >            assertUnlocked(sl);
917 >        }
918      }
919  
920      /**
921       * asReadWriteLock.writeLock can be locked and unlocked
922       */
923 <    public void testAsReadWriteLockWriteLock() {
923 >    public void testAsReadWriteLockWriteLock() throws Throwable {
924          StampedLock sl = new StampedLock();
925          Lock lock = sl.asReadWriteLock().writeLock();
926 <        lock.lock();
927 <        assertFalse(lock.tryLock());
928 <        lock.unlock();
929 <        assertTrue(lock.tryLock());
926 >        for (Action locker : lockLockers(lock)) {
927 >            locker.run();
928 >            assertTrue(sl.isWriteLocked());
929 >            assertFalse(sl.isReadLocked());
930 >            assertFalse(lock.tryLock());
931 >            lock.unlock();
932 >            assertUnlocked(sl);
933 >        }
934      }
935  
936      /**
937       * asReadWriteLock.readLock can be locked and unlocked
938       */
939 <    public void testAsReadWriteLockReadLock() {
939 >    public void testAsReadWriteLockReadLock() throws Throwable {
940          StampedLock sl = new StampedLock();
941          Lock lock = sl.asReadWriteLock().readLock();
942 <        lock.lock();
943 <        lock.unlock();
944 <        assertTrue(lock.tryLock());
942 >        for (Action locker : lockLockers(lock)) {
943 >            locker.run();
944 >            assertTrue(sl.isReadLocked());
945 >            assertFalse(sl.isWriteLocked());
946 >            assertEquals(1, sl.getReadLockCount());
947 >            locker.run();
948 >            assertTrue(sl.isReadLocked());
949 >            assertEquals(2, sl.getReadLockCount());
950 >            lock.unlock();
951 >            lock.unlock();
952 >            assertUnlocked(sl);
953 >        }
954      }
955  
956 +    /**
957 +     * Lock.newCondition throws UnsupportedOperationException
958 +     */
959 +    public void testLockViewsDoNotSupportConditions() {
960 +        StampedLock sl = new StampedLock();
961 +        assertThrows(UnsupportedOperationException.class,
962 +                     () -> sl.asWriteLock().newCondition(),
963 +                     () -> sl.asReadLock().newCondition(),
964 +                     () -> sl.asReadWriteLock().writeLock().newCondition(),
965 +                     () -> sl.asReadWriteLock().readLock().newCondition());
966 +    }
967 +
968 +    /**
969 +     * Passing optimistic read stamps to unlock operations result in
970 +     * IllegalMonitorStateException
971 +     */
972 +    public void testCannotUnlockOptimisticReadStamps() {
973 +        Runnable[] actions = {
974 +            () -> {
975 +                StampedLock sl = new StampedLock();
976 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
977 +                sl.unlockRead(stamp);
978 +            },
979 +            () -> {
980 +                StampedLock sl = new StampedLock();
981 +                long stamp = sl.tryOptimisticRead();
982 +                sl.unlock(stamp);
983 +            },
984 +
985 +            () -> {
986 +                StampedLock sl = new StampedLock();
987 +                long stamp = sl.tryOptimisticRead();
988 +                sl.writeLock();
989 +                sl.unlock(stamp);
990 +            },
991 +            () -> {
992 +                StampedLock sl = new StampedLock();
993 +                sl.readLock();
994 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
995 +                sl.unlockRead(stamp);
996 +            },
997 +            () -> {
998 +                StampedLock sl = new StampedLock();
999 +                sl.readLock();
1000 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
1001 +                sl.unlock(stamp);
1002 +            },
1003 +
1004 +            () -> {
1005 +                StampedLock sl = new StampedLock();
1006 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1007 +                assertValid(sl, stamp);
1008 +                sl.writeLock();
1009 +                sl.unlockWrite(stamp);
1010 +            },
1011 +            () -> {
1012 +                StampedLock sl = new StampedLock();
1013 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1014 +                sl.writeLock();
1015 +                sl.unlock(stamp);
1016 +            },
1017 +            () -> {
1018 +                StampedLock sl = new StampedLock();
1019 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1020 +                sl.readLock();
1021 +                sl.unlockRead(stamp);
1022 +            },
1023 +            () -> {
1024 +                StampedLock sl = new StampedLock();
1025 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1026 +                sl.readLock();
1027 +                sl.unlock(stamp);
1028 +            },
1029 +
1030 +            () -> {
1031 +                StampedLock sl = new StampedLock();
1032 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1033 +                assertValid(sl, stamp);
1034 +                sl.writeLock();
1035 +                sl.unlockWrite(stamp);
1036 +            },
1037 +            () -> {
1038 +                StampedLock sl = new StampedLock();
1039 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1040 +                sl.writeLock();
1041 +                sl.unlock(stamp);
1042 +            },
1043 +            () -> {
1044 +                StampedLock sl = new StampedLock();
1045 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1046 +                sl.readLock();
1047 +                sl.unlockRead(stamp);
1048 +            },
1049 +            () -> {
1050 +                StampedLock sl = new StampedLock();
1051 +                sl.readLock();
1052 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1053 +                assertValid(sl, stamp);
1054 +                sl.readLock();
1055 +                sl.unlockRead(stamp);
1056 +            },
1057 +            () -> {
1058 +                StampedLock sl = new StampedLock();
1059 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1060 +                sl.readLock();
1061 +                sl.unlock(stamp);
1062 +            },
1063 +            () -> {
1064 +                StampedLock sl = new StampedLock();
1065 +                sl.readLock();
1066 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1067 +                sl.readLock();
1068 +                sl.unlock(stamp);
1069 +            },
1070 +        };
1071 +
1072 +        assertThrows(IllegalMonitorStateException.class, actions);
1073 +    }
1074 +
1075 +    static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
1076 +        try { return sl.writeLockInterruptibly(); }
1077 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1078 +    }
1079 +
1080 +    static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1081 +        try { return sl.tryWriteLock(time, unit); }
1082 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1083 +    }
1084 +
1085 +    static long readLockInterruptiblyUninterrupted(StampedLock sl) {
1086 +        try { return sl.readLockInterruptibly(); }
1087 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1088 +    }
1089 +
1090 +    static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1091 +        try { return sl.tryReadLock(time, unit); }
1092 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1093 +    }
1094 +
1095 +    /**
1096 +     * Invalid stamps result in IllegalMonitorStateException
1097 +     */
1098 +    public void testInvalidStampsThrowIllegalMonitorStateException() {
1099 +        final StampedLock sl = new StampedLock();
1100 +
1101 +        assertThrows(IllegalMonitorStateException.class,
1102 +                     () -> sl.unlockWrite(0L),
1103 +                     () -> sl.unlockRead(0L),
1104 +                     () -> sl.unlock(0L));
1105 +
1106 +        final long optimisticStamp = sl.tryOptimisticRead();
1107 +        final long readStamp = sl.readLock();
1108 +        sl.unlockRead(readStamp);
1109 +        final long writeStamp = sl.writeLock();
1110 +        sl.unlockWrite(writeStamp);
1111 +        assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1112 +        final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1113 +        final Runnable assertNoLongerValidStampsThrow = () -> {
1114 +            for (long noLongerValidStamp : noLongerValidStamps)
1115 +                assertThrows(IllegalMonitorStateException.class,
1116 +                             () -> sl.unlockWrite(noLongerValidStamp),
1117 +                             () -> sl.unlockRead(noLongerValidStamp),
1118 +                             () -> sl.unlock(noLongerValidStamp));
1119 +        };
1120 +        assertNoLongerValidStampsThrow.run();
1121 +
1122 +        for (Function<StampedLock, Long> readLocker : readLockers())
1123 +        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1124 +            final long stamp = readLocker.apply(sl);
1125 +            assertValid(sl, stamp);
1126 +            assertNoLongerValidStampsThrow.run();
1127 +            assertThrows(IllegalMonitorStateException.class,
1128 +                         () -> sl.unlockWrite(stamp),
1129 +                         () -> sl.unlockRead(sl.tryOptimisticRead()),
1130 +                         () -> sl.unlockRead(0L));
1131 +            readUnlocker.accept(sl, stamp);
1132 +            assertUnlocked(sl);
1133 +            assertNoLongerValidStampsThrow.run();
1134 +        }
1135 +
1136 +        for (Function<StampedLock, Long> writeLocker : writeLockers())
1137 +        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1138 +            final long stamp = writeLocker.apply(sl);
1139 +            assertValid(sl, stamp);
1140 +            assertNoLongerValidStampsThrow.run();
1141 +            assertThrows(IllegalMonitorStateException.class,
1142 +                         () -> sl.unlockRead(stamp),
1143 +                         () -> sl.unlockWrite(0L));
1144 +            writeUnlocker.accept(sl, stamp);
1145 +            assertUnlocked(sl);
1146 +            assertNoLongerValidStampsThrow.run();
1147 +        }
1148 +    }
1149 +
1150 +    /**
1151 +     * Read locks can be very deeply nested
1152 +     */
1153 +    public void testDeeplyNestedReadLocks() {
1154 +        final StampedLock lock = new StampedLock();
1155 +        final int depth = 300;
1156 +        final long[] stamps = new long[depth];
1157 +        final List<Function<StampedLock, Long>> readLockers = readLockers();
1158 +        final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1159 +        for (int i = 0; i < depth; i++) {
1160 +            Function<StampedLock, Long> readLocker
1161 +                = readLockers.get(i % readLockers.size());
1162 +            long stamp = readLocker.apply(lock);
1163 +            assertEquals(i + 1, lock.getReadLockCount());
1164 +            assertTrue(lock.isReadLocked());
1165 +            stamps[i] = stamp;
1166 +        }
1167 +        for (int i = 0; i < depth; i++) {
1168 +            BiConsumer<StampedLock, Long> readUnlocker
1169 +                = readUnlockers.get(i % readUnlockers.size());
1170 +            assertEquals(depth - i, lock.getReadLockCount());
1171 +            assertTrue(lock.isReadLocked());
1172 +            readUnlocker.accept(lock, stamps[depth - 1 - i]);
1173 +        }
1174 +        assertUnlocked(lock);
1175 +    }
1176   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines