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.6 by dl, Thu Mar 21 19:06:54 2013 UTC vs.
Revision 1.29 by jsr166, Sun Nov 6 22:42:10 2016 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());
131 <        assertFalse(lock.isReadLocked());
132 <        assertEquals(lock.getReadLockCount(), 0);
133 <        assertFalse(lock.tryUnlockRead());
134 <        assertTrue(lock.tryUnlockWrite());
135 <        assertFalse(lock.tryUnlockWrite());
136 <        assertFalse(lock.tryUnlockRead());
137 <        assertFalse(lock.isWriteLocked());
66 >    void assertUnlocked(StampedLock lock) {
67          assertFalse(lock.isReadLocked());
139        assertEquals(lock.getReadLockCount(), 0);
140        long rs = lock.readLock();
68          assertFalse(lock.isWriteLocked());
69 <        assertTrue(lock.isReadLocked());
70 <        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() {
274 >    public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() {
275          final CountDownLatch running = new CountDownLatch(1);
276          final StampedLock lock = new StampedLock();
277 <        long s = lock.writeLock();
278 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
279 <            public void realRun() throws InterruptedException {
280 <                running.countDown();
281 <                lock.writeLockInterruptibly();
282 <            }});
283 <        try {
284 <            running.await();
285 <            waitForThreadToEnterWaitState(t, 100);
286 <            t.interrupt();
287 <            awaitTermination(t);
288 <            releaseWriteLock(lock, s);
289 <        } catch (InterruptedException ie) {
290 <            threadUnexpectedException(ie);
277 >
278 >        Action[] interruptibleLockActions = {
279 >            () -> lock.writeLockInterruptibly(),
280 >            () -> lock.tryWriteLock(Long.MIN_VALUE, DAYS),
281 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
282 >            () -> lock.readLockInterruptibly(),
283 >            () -> lock.tryReadLock(Long.MIN_VALUE, DAYS),
284 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
285 >            () -> lock.asWriteLock().lockInterruptibly(),
286 >            () -> lock.asWriteLock().tryLock(0L, DAYS),
287 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
288 >            () -> lock.asReadLock().lockInterruptibly(),
289 >            () -> lock.asReadLock().tryLock(0L, DAYS),
290 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
291 >        };
292 >        shuffle(interruptibleLockActions);
293 >
294 >        assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
295 >        {
296 >            long s = lock.writeLock();
297 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
298 >            lock.unlockWrite(s);
299 >        }
300 >        {
301 >            long s = lock.readLock();
302 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
303 >            lock.unlockRead(s);
304          }
305      }
306  
307 +    void assertThrowInterruptedExceptionWhenInterrupted(Action[] actions) {
308 +        int n = actions.length;
309 +        Future<?>[] futures = new Future<?>[n];
310 +        CountDownLatch threadsStarted = new CountDownLatch(n);
311 +        CountDownLatch done = new CountDownLatch(n);
312 +
313 +        for (int i = 0; i < n; i++) {
314 +            Action action = actions[i];
315 +            futures[i] = cachedThreadPool.submit(new CheckedRunnable() {
316 +                public void realRun() throws Throwable {
317 +                    threadsStarted.countDown();
318 +                    try {
319 +                        action.run();
320 +                        shouldThrow();
321 +                    }
322 +                    catch (InterruptedException success) {}
323 +                    catch (Throwable fail) { threadUnexpectedException(fail); }
324 +                    assertFalse(Thread.interrupted());
325 +                    done.countDown();
326 +                }});
327 +        }
328 +
329 +        await(threadsStarted);
330 +        assertEquals(n, done.getCount());
331 +        for (Future<?> future : futures) // Interrupt all the tasks
332 +            future.cancel(true);
333 +        await(done);
334 +    }
335 +
336      /**
337 <     * timed tryWriteLock is interruptible
337 >     * interruptible operations throw InterruptedException when write locked and interrupted
338       */
339 <    public void testWriteTryLock_Interruptible() {
339 >    public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
340          final CountDownLatch running = new CountDownLatch(1);
341          final StampedLock lock = new StampedLock();
342          long s = lock.writeLock();
343 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
344 <            public void realRun() throws InterruptedException {
345 <                running.countDown();
346 <                lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS);
347 <            }});
348 <        try {
349 <            running.await();
350 <            waitForThreadToEnterWaitState(t, 100);
351 <            t.interrupt();
352 <            awaitTermination(t);
353 <            releaseWriteLock(lock, s);
354 <        } catch (InterruptedException ie) {
355 <            threadUnexpectedException(ie);
356 <        }
343 >
344 >        Action[] interruptibleLockBlockingActions = {
345 >            () -> lock.writeLockInterruptibly(),
346 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
347 >            () -> lock.readLockInterruptibly(),
348 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
349 >            () -> lock.asWriteLock().lockInterruptibly(),
350 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
351 >            () -> lock.asReadLock().lockInterruptibly(),
352 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
353 >        };
354 >        shuffle(interruptibleLockBlockingActions);
355 >
356 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
357      }
358  
359      /**
360 <     * readLockInterruptibly is interruptible
360 >     * interruptible operations throw InterruptedException when read locked and interrupted
361       */
362 <    public void testReadLockInterruptibly_Interruptible() {
362 >    public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
363          final CountDownLatch running = new CountDownLatch(1);
364          final StampedLock lock = new StampedLock();
365 <        long s = lock.writeLock();
366 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
367 <            public void realRun() throws InterruptedException {
368 <                running.countDown();
369 <                lock.readLockInterruptibly();
370 <            }});
371 <        try {
372 <            running.await();
373 <            waitForThreadToEnterWaitState(t, 100);
374 <            t.interrupt();
375 <            awaitTermination(t);
346 <            releaseWriteLock(lock, s);
347 <        } catch (InterruptedException ie) {
348 <            threadUnexpectedException(ie);
349 <        }
365 >        long s = lock.readLock();
366 >
367 >        Action[] interruptibleLockBlockingActions = {
368 >            () -> lock.writeLockInterruptibly(),
369 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
370 >            () -> lock.asWriteLock().lockInterruptibly(),
371 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
372 >        };
373 >        shuffle(interruptibleLockBlockingActions);
374 >
375 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
376      }
377  
378      /**
379 <     * timed tryReadLock is interruptible
379 >     * Non-interruptible operations ignore and preserve interrupt status
380       */
381 <    public void testReadTryLock_Interruptible() {
356 <        final CountDownLatch running = new CountDownLatch(1);
381 >    public void testNonInterruptibleOperationsIgnoreInterrupts() {
382          final StampedLock lock = new StampedLock();
383 <        long s = lock.writeLock();
384 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
385 <            public void realRun() throws InterruptedException {
386 <                running.countDown();
387 <                lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS);
388 <            }});
389 <        try {
365 <            running.await();
366 <            waitForThreadToEnterWaitState(t, 100);
367 <            t.interrupt();
368 <            awaitTermination(t);
369 <            releaseWriteLock(lock, s);
370 <        } catch (InterruptedException ie) {
371 <            threadUnexpectedException(ie);
383 >        Thread.currentThread().interrupt();
384 >
385 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
386 >            long s = assertValid(lock, lock.readLock());
387 >            readUnlocker.accept(lock, s);
388 >            s = assertValid(lock, lock.tryReadLock());
389 >            readUnlocker.accept(lock, s);
390          }
391 +
392 +        lock.asReadLock().lock();
393 +        lock.asReadLock().unlock();
394 +
395 +        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
396 +            long s = assertValid(lock, lock.writeLock());
397 +            writeUnlocker.accept(lock, s);
398 +            s = assertValid(lock, lock.tryWriteLock());
399 +            writeUnlocker.accept(lock, s);
400 +        }
401 +
402 +        lock.asWriteLock().lock();
403 +        lock.asWriteLock().unlock();
404 +
405 +        assertTrue(Thread.interrupted());
406      }
407  
408      /**
409       * tryWriteLock on an unlocked lock succeeds
410       */
411 <    public void testWriteTryLock() {
411 >    public void testTryWriteLock() {
412          final StampedLock lock = new StampedLock();
413          long s = lock.tryWriteLock();
414          assertTrue(s != 0L);
415          assertTrue(lock.isWriteLocked());
416 <        long s2 = lock.tryWriteLock();
384 <        assertEquals(s2, 0L);
416 >        assertEquals(0L, lock.tryWriteLock());
417          releaseWriteLock(lock, s);
418      }
419  
420      /**
421       * tryWriteLock fails if locked
422       */
423 <    public void testWriteTryLockWhenLocked() {
423 >    public void testTryWriteLockWhenLocked() {
424          final StampedLock lock = new StampedLock();
425          long s = lock.writeLock();
426          Thread t = newStartedThread(new CheckedRunnable() {
427              public void realRun() {
428 <                long ws = lock.tryWriteLock();
397 <                assertTrue(ws == 0L);
428 >                assertEquals(0L, lock.tryWriteLock());
429              }});
430  
431 +        assertEquals(0L, lock.tryWriteLock());
432          awaitTermination(t);
433          releaseWriteLock(lock, s);
434      }
# Line 404 | Line 436 | public class StampedLockTest extends JSR
436      /**
437       * tryReadLock fails if write-locked
438       */
439 <    public void testReadTryLockWhenLocked() {
439 >    public void testTryReadLockWhenLocked() {
440          final StampedLock lock = new StampedLock();
441          long s = lock.writeLock();
442          Thread t = newStartedThread(new CheckedRunnable() {
443              public void realRun() {
444 <                long rs = lock.tryReadLock();
413 <                assertEquals(rs, 0L);
444 >                assertEquals(0L, lock.tryReadLock());
445              }});
446  
447 +        assertEquals(0L, lock.tryReadLock());
448          awaitTermination(t);
449          releaseWriteLock(lock, s);
450      }
# Line 426 | Line 458 | public class StampedLockTest extends JSR
458          Thread t = newStartedThread(new CheckedRunnable() {
459              public void realRun() throws InterruptedException {
460                  long s2 = lock.tryReadLock();
461 <                assertTrue(s2 != 0L);
461 >                assertValid(lock, s2);
462                  lock.unlockRead(s2);
463                  long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
464 <                assertTrue(s3 != 0L);
464 >                assertValid(lock, s3);
465                  lock.unlockRead(s3);
466                  long s4 = lock.readLock();
467 +                assertValid(lock, s4);
468                  lock.unlockRead(s4);
469 +                lock.asReadLock().lock();
470 +                lock.asReadLock().unlock();
471 +                lock.asReadLock().lockInterruptibly();
472 +                lock.asReadLock().unlock();
473 +                lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
474 +                lock.asReadLock().unlock();
475              }});
476  
477          awaitTermination(t);
# Line 442 | Line 481 | public class StampedLockTest extends JSR
481      /**
482       * A writelock succeeds only after a reading thread unlocks
483       */
484 <    public void testWriteAfterReadLock() {
484 >    public void testWriteAfterReadLock() throws InterruptedException {
485          final CountDownLatch running = new CountDownLatch(1);
486          final StampedLock lock = new StampedLock();
487          long rs = lock.readLock();
# Line 452 | Line 491 | public class StampedLockTest extends JSR
491                  long s = lock.writeLock();
492                  lock.unlockWrite(s);
493              }});
494 <        try {
495 <            running.await();
496 <            waitForThreadToEnterWaitState(t, 100);
497 <            assertFalse(lock.isWriteLocked());
498 <            lock.unlockRead(rs);
499 <            awaitTermination(t);
500 <            assertFalse(lock.isWriteLocked());
462 <        } catch (InterruptedException ie) {
463 <            threadUnexpectedException(ie);
464 <        }
494 >
495 >        running.await();
496 >        waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS);
497 >        assertFalse(lock.isWriteLocked());
498 >        lock.unlockRead(rs);
499 >        awaitTermination(t);
500 >        assertFalse(lock.isWriteLocked());
501      }
502  
503      /**
# Line 475 | Line 511 | public class StampedLockTest extends JSR
511                  long rs = lock.readLock();
512                  lock.unlockRead(rs);
513              }});
514 +
515          awaitTermination(t1);
516  
517          Thread t2 = newStartedThread(new CheckedRunnable() {
# Line 482 | Line 519 | public class StampedLockTest extends JSR
519                  long ws = lock.writeLock();
520                  lock.unlockWrite(ws);
521              }});
522 +
523 +        assertTrue(lock.isReadLocked());
524          assertFalse(lock.isWriteLocked());
525          lock.unlockRead(s);
526          awaitTermination(t2);
# Line 493 | Line 532 | public class StampedLockTest extends JSR
532       */
533      public void testReadAfterWriteLock() {
534          final StampedLock lock = new StampedLock();
535 +        final CountDownLatch threadsStarted = new CountDownLatch(2);
536          final long s = lock.writeLock();
537          Thread t1 = newStartedThread(new CheckedRunnable() {
538              public void realRun() {
539 +                threadsStarted.countDown();
540                  long rs = lock.readLock();
541                  lock.unlockRead(rs);
542              }});
543          Thread t2 = newStartedThread(new CheckedRunnable() {
544              public void realRun() {
545 +                threadsStarted.countDown();
546                  long rs = lock.readLock();
547                  lock.unlockRead(rs);
548              }});
549  
550 +        await(threadsStarted);
551 +        waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS);
552 +        waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS);
553          releaseWriteLock(lock, s);
554          awaitTermination(t1);
555          awaitTermination(t2);
556      }
557  
558      /**
559 <     * tryReadLock succeeds if readlocked but not writelocked
559 >     * tryReadLock succeeds if read locked but not write locked
560       */
561      public void testTryLockWhenReadLocked() {
562          final StampedLock lock = new StampedLock();
# Line 519 | Line 564 | public class StampedLockTest extends JSR
564          Thread t = newStartedThread(new CheckedRunnable() {
565              public void realRun() {
566                  long rs = lock.tryReadLock();
567 <                threadAssertTrue(rs != 0L);
567 >                assertValid(lock, rs);
568                  lock.unlockRead(rs);
569              }});
570  
# Line 528 | Line 573 | public class StampedLockTest extends JSR
573      }
574  
575      /**
576 <     * tryWriteLock fails when readlocked
576 >     * tryWriteLock fails when read locked
577       */
578 <    public void testWriteTryLockWhenReadLocked() {
578 >    public void testTryWriteLockWhenReadLocked() {
579          final StampedLock lock = new StampedLock();
580          long s = lock.readLock();
581          Thread t = newStartedThread(new CheckedRunnable() {
582              public void realRun() {
583 <                long ws = lock.tryWriteLock();
539 <                threadAssertEquals(ws, 0L);
583 >                threadAssertEquals(0L, lock.tryWriteLock());
584              }});
585  
586          awaitTermination(t);
# Line 544 | Line 588 | public class StampedLockTest extends JSR
588      }
589  
590      /**
591 <     * timed tryWriteLock times out if locked
591 >     * timed lock operations time out if lock not available
592       */
593 <    public void testWriteTryLock_Timeout() {
593 >    public void testTimedLock_Timeout() throws Exception {
594 >        ArrayList<Future<?>> futures = new ArrayList<>();
595 >
596 >        // Write locked
597          final StampedLock lock = new StampedLock();
598 <        long s = lock.writeLock();
599 <        Thread t = newStartedThread(new CheckedRunnable() {
598 >        long stamp = lock.writeLock();
599 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
600 >        assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
601 >        assertFalse(lock.asReadLock().tryLock(0L, DAYS));
602 >        assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
603 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
604 >        assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
605 >        assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
606 >        assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
607 >
608 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
609              public void realRun() throws InterruptedException {
610                  long startTime = System.nanoTime();
611 <                long timeoutMillis = 10;
612 <                long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
613 <                assertEquals(ws, 0L);
558 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
559 <            }});
611 >                assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
612 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
613 >            }}));
614  
615 <        awaitTermination(t);
616 <        releaseWriteLock(lock, s);
617 <    }
615 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
616 >            public void realRun() throws InterruptedException {
617 >                long startTime = System.nanoTime();
618 >                assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
619 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
620 >            }}));
621 >
622 >        // Read locked
623 >        final StampedLock lock2 = new StampedLock();
624 >        long stamp2 = lock2.readLock();
625 >        assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
626 >        assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
627 >        assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
628 >        assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
629  
630 <    /**
566 <     * timed tryReadLock times out if write-locked
567 <     */
568 <    public void testReadTryLock_Timeout() {
569 <        final StampedLock lock = new StampedLock();
570 <        long s = lock.writeLock();
571 <        Thread t = newStartedThread(new CheckedRunnable() {
630 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
631              public void realRun() throws InterruptedException {
632                  long startTime = System.nanoTime();
633 <                long timeoutMillis = 10;
634 <                long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
635 <                assertEquals(rs, 0L);
636 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
637 <            }});
638 <        
639 <        awaitTermination(t);
640 <        assertTrue(lock.isWriteLocked());
641 <        lock.unlockWrite(s);
633 >                assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
634 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
635 >            }}));
636 >
637 >        for (Future<?> future : futures)
638 >            assertNull(future.get());
639 >
640 >        releaseWriteLock(lock, stamp);
641 >        releaseReadLock(lock2, stamp2);
642      }
643  
644      /**
645 <     * writeLockInterruptibly succeeds if unlocked, else is interruptible
645 >     * writeLockInterruptibly succeeds if unlocked
646       */
647 <    public void testWriteLockInterruptibly() {
589 <        final CountDownLatch running = new CountDownLatch(1);
647 >    public void testWriteLockInterruptibly() throws InterruptedException {
648          final StampedLock lock = new StampedLock();
649 <        long s = 0L;
650 <        try {
651 <            s = lock.writeLockInterruptibly();
594 <        } catch (InterruptedException ie) {
595 <            threadUnexpectedException(ie);
596 <        }
597 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
598 <            public void realRun() throws InterruptedException {
599 <                running.countDown();
600 <                lock.writeLockInterruptibly();
601 <            }});
602 <
603 <        try {
604 <            running.await();
605 <            waitForThreadToEnterWaitState(t, 100);
606 <            t.interrupt();
607 <            assertTrue(lock.isWriteLocked());
608 <            awaitTermination(t);
609 <            releaseWriteLock(lock, s);
610 <        } catch (InterruptedException ie) {
611 <            threadUnexpectedException(ie);
612 <        }
613 <
649 >        long s = lock.writeLockInterruptibly();
650 >        assertTrue(lock.isWriteLocked());
651 >        releaseWriteLock(lock, s);
652      }
653  
654      /**
655 <     * readLockInterruptibly succeeds if lock free else is interruptible
655 >     * readLockInterruptibly succeeds if lock free
656       */
657 <    public void testReadLockInterruptibly() {
620 <        final CountDownLatch running = new CountDownLatch(1);
657 >    public void testReadLockInterruptibly() throws InterruptedException {
658          final StampedLock lock = new StampedLock();
659 <        long s = 0L;
660 <        try {
661 <            s = lock.readLockInterruptibly();
662 <            lock.unlockRead(s);
663 <            s = lock.writeLockInterruptibly();
664 <        } catch (InterruptedException ie) {
665 <            threadUnexpectedException(ie);
666 <        }
630 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
631 <            public void realRun() throws InterruptedException {
632 <                running.countDown();
633 <                lock.readLockInterruptibly();
634 <            }});
635 <        try {
636 <            running.await();
637 <            waitForThreadToEnterWaitState(t, 100);
638 <            t.interrupt();
639 <            awaitTermination(t);
640 <            releaseWriteLock(lock, s);
641 <        } catch (InterruptedException ie) {
642 <            threadUnexpectedException(ie);
643 <        }
659 >
660 >        long s = assertValid(lock, lock.readLockInterruptibly());
661 >        assertTrue(lock.isReadLocked());
662 >        lock.unlockRead(s);
663 >
664 >        lock.asReadLock().lockInterruptibly();
665 >        assertTrue(lock.isReadLocked());
666 >        lock.asReadLock().unlock();
667      }
668  
669      /**
# Line 672 | Line 695 | public class StampedLockTest extends JSR
695      }
696  
697      /**
698 <     * tryOptimisticRead succeeds and validates if unlocked, fails if locked
698 >     * tryOptimisticRead succeeds and validates if unlocked, fails if
699 >     * exclusively locked
700       */
701 <    public void testValidateOptimistic() {
702 <        try {
703 <            StampedLock lock = new StampedLock();
704 <            long s, p;
705 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
706 <            assertTrue(lock.validate(p));
707 <            assertTrue((s = lock.writeLock()) != 0L);
708 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
709 <            assertTrue(lock.validate(s));
710 <            lock.unlockWrite(s);
711 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
712 <            assertTrue(lock.validate(p));
713 <            assertTrue((s = lock.readLock()) != 0L);
714 <            assertTrue(lock.validate(s));
715 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
692 <            assertTrue(lock.validate(p));
693 <            lock.unlockRead(s);
694 <            assertTrue((s = lock.tryWriteLock()) != 0L);
695 <            assertTrue(lock.validate(s));
696 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
697 <            lock.unlockWrite(s);
698 <            assertTrue((s = lock.tryReadLock()) != 0L);
699 <            assertTrue(lock.validate(s));
700 <            assertTrue((p = lock.tryOptimisticRead()) != 0L);
701 <            lock.unlockRead(s);
701 >    public void testValidateOptimistic() throws InterruptedException {
702 >        StampedLock lock = new StampedLock();
703 >
704 >        assertValid(lock, lock.tryOptimisticRead());
705 >
706 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
707 >            long s = assertValid(lock, writeLocker.apply(lock));
708 >            assertEquals(0L, lock.tryOptimisticRead());
709 >            releaseWriteLock(lock, s);
710 >        }
711 >
712 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
713 >            long s = assertValid(lock, readLocker.apply(lock));
714 >            long p = assertValid(lock, lock.tryOptimisticRead());
715 >            releaseReadLock(lock, s);
716              assertTrue(lock.validate(p));
703            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
704            assertFalse((p = lock.tryOptimisticRead()) != 0L);
705            assertTrue(lock.validate(s));
706            lock.unlockWrite(s);
707            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
708            assertTrue(lock.validate(s));
709            assertTrue((p = lock.tryOptimisticRead()) != 0L);
710            lock.unlockRead(s);
711            assertTrue((p = lock.tryOptimisticRead()) != 0L);
712        } catch (InterruptedException ie) {
713            threadUnexpectedException(ie);
717          }
718 +
719 +        assertValid(lock, lock.tryOptimisticRead());
720      }
721  
722      /**
723       * tryOptimisticRead stamp does not validate if a write lock intervenes
724       */
725      public void testValidateOptimisticWriteLocked() {
726 <        StampedLock lock = new StampedLock();
727 <        long s, p;
728 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
724 <        assertTrue((s = lock.writeLock()) != 0L);
726 >        final StampedLock lock = new StampedLock();
727 >        final long p = assertValid(lock, lock.tryOptimisticRead());
728 >        final long s = assertValid(lock, lock.writeLock());
729          assertFalse(lock.validate(p));
730 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
730 >        assertEquals(0L, lock.tryOptimisticRead());
731          assertTrue(lock.validate(s));
732          lock.unlockWrite(s);
733      }
# Line 732 | Line 736 | public class StampedLockTest extends JSR
736       * tryOptimisticRead stamp does not validate if a write lock
737       * intervenes in another thread
738       */
739 <    public void testValidateOptimisticWriteLocked2() {
739 >    public void testValidateOptimisticWriteLocked2()
740 >            throws InterruptedException {
741          final CountDownLatch running = new CountDownLatch(1);
742          final StampedLock lock = new StampedLock();
743 <        long s, p;
744 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
743 >        final long p = assertValid(lock, lock.tryOptimisticRead());
744 >
745          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
746 <                public void realRun() throws InterruptedException {
747 <                    lock.writeLockInterruptibly();
748 <                    running.countDown();
749 <                    lock.writeLockInterruptibly();
750 <                }});
751 <        try {
752 <            running.await();
753 <            assertFalse(lock.validate(p));
754 <            assertFalse((p = lock.tryOptimisticRead()) != 0L);
755 <            t.interrupt();
756 <            awaitTermination(t);
752 <        } catch (InterruptedException ie) {
753 <            threadUnexpectedException(ie);
754 <        }
746 >            public void realRun() throws InterruptedException {
747 >                lock.writeLockInterruptibly();
748 >                running.countDown();
749 >                lock.writeLockInterruptibly();
750 >            }});
751 >
752 >        running.await();
753 >        assertFalse(lock.validate(p));
754 >        assertEquals(0L, lock.tryOptimisticRead());
755 >        t.interrupt();
756 >        awaitTermination(t);
757      }
758  
759      /**
760 <     * tryConvertToOptimisticRead succeeds and validates if successfully locked,
761 <     */
762 <    public void testTryConvertToOptimisticRead() {
763 <        try {
764 <            StampedLock lock = new StampedLock();
765 <            long s, p;
766 <            s = 0L;
767 <            assertFalse((p = lock.tryConvertToOptimisticRead(s)) != 0L);
768 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
769 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
770 <            assertTrue((s = lock.writeLock()) != 0L);
771 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
772 <            assertTrue(lock.validate(p));
773 <            assertTrue((s = lock.readLock()) != 0L);
774 <            assertTrue(lock.validate(s));
773 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
774 <            assertTrue(lock.validate(p));
775 <            assertTrue((s = lock.tryWriteLock()) != 0L);
776 <            assertTrue(lock.validate(s));
777 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
778 <            assertTrue(lock.validate(p));
779 <            assertTrue((s = lock.tryReadLock()) != 0L);
780 <            assertTrue(lock.validate(s));
781 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
760 >     * tryConvertToOptimisticRead succeeds and validates if successfully locked
761 >     */
762 >    public void testTryConvertToOptimisticRead() throws InterruptedException {
763 >        StampedLock lock = new StampedLock();
764 >        long s, p, q;
765 >        assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
766 >
767 >        s = assertValid(lock, lock.tryOptimisticRead());
768 >        assertEquals(s, lock.tryConvertToOptimisticRead(s));
769 >        assertTrue(lock.validate(s));
770 >
771 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
772 >            s = assertValid(lock, writeLocker.apply(lock));
773 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
774 >            assertFalse(lock.validate(s));
775              assertTrue(lock.validate(p));
776 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
777 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
776 >            assertUnlocked(lock);
777 >        }
778 >
779 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
780 >            s = assertValid(lock, readLocker.apply(lock));
781 >            q = assertValid(lock, lock.tryOptimisticRead());
782 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
783 >            assertTrue(lock.validate(q));
784 >            assertTrue(lock.isReadLocked());
785 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
786              assertTrue(lock.validate(p));
786            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
787              assertTrue(lock.validate(s));
788 <            assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
789 <            assertTrue(lock.validate(p));
790 <        } catch (InterruptedException ie) {
791 <            threadUnexpectedException(ie);
788 >            assertUnlocked(lock);
789 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
790 >            assertTrue(lock.validate(q));
791          }
792      }
793  
794      /**
795 <     * tryConvertToReadLock succeeds and validates if successfully locked
797 <     * or lock free;
795 >     * tryConvertToReadLock succeeds for valid stamps
796       */
797 <    public void testTryConvertToReadLock() {
798 <        try {
799 <            StampedLock lock = new StampedLock();
800 <            long s, p;
801 <            s = 0L;
802 <            assertFalse((p = lock.tryConvertToReadLock(s)) != 0L);
803 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
804 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
805 <            lock.unlockRead(p);
806 <            assertTrue((s = lock.writeLock()) != 0L);
807 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
808 <            assertTrue(lock.validate(p));
809 <            lock.unlockRead(p);
810 <            assertTrue((s = lock.readLock()) != 0L);
811 <            assertTrue(lock.validate(s));
812 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
813 <            assertTrue(lock.validate(p));
814 <            lock.unlockRead(p);
815 <            assertTrue((s = lock.tryWriteLock()) != 0L);
816 <            assertTrue(lock.validate(s));
817 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
818 <            assertTrue(lock.validate(p));
819 <            lock.unlockRead(p);
820 <            assertTrue((s = lock.tryReadLock()) != 0L);
821 <            assertTrue(lock.validate(s));
822 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
823 <            assertTrue(lock.validate(p));
824 <            lock.unlockRead(p);
825 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
826 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
827 <            assertTrue(lock.validate(p));
828 <            lock.unlockRead(p);
829 <            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
830 <            assertTrue(lock.validate(s));
831 <            assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
832 <            assertTrue(lock.validate(p));
833 <            lock.unlockRead(p);
834 <        } catch (InterruptedException ie) {
835 <            threadUnexpectedException(ie);
797 >    public void testTryConvertToReadLock() throws InterruptedException {
798 >        StampedLock lock = new StampedLock();
799 >        long s, p;
800 >
801 >        assertEquals(0L, lock.tryConvertToReadLock(0L));
802 >
803 >        s = assertValid(lock, lock.tryOptimisticRead());
804 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
805 >        assertTrue(lock.isReadLocked());
806 >        assertEquals(1, lock.getReadLockCount());
807 >        assertTrue(lock.validate(s));
808 >        lock.unlockRead(p);
809 >
810 >        s = assertValid(lock, lock.tryOptimisticRead());
811 >        lock.readLock();
812 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
813 >        assertTrue(lock.isReadLocked());
814 >        assertEquals(2, lock.getReadLockCount());
815 >        lock.unlockRead(p);
816 >        lock.unlockRead(p);
817 >        assertUnlocked(lock);
818 >
819 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
820 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
821 >                s = assertValid(lock, writeLocker.apply(lock));
822 >                p = assertValid(lock, lock.tryConvertToReadLock(s));
823 >                assertFalse(lock.validate(s));
824 >                assertTrue(lock.isReadLocked());
825 >                assertEquals(1, lock.getReadLockCount());
826 >                readUnlocker.accept(lock, p);
827 >            }
828 >
829 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
830 >                s = assertValid(lock, readLocker.apply(lock));
831 >                assertEquals(s, lock.tryConvertToReadLock(s));
832 >                assertTrue(lock.validate(s));
833 >                assertTrue(lock.isReadLocked());
834 >                assertEquals(1, lock.getReadLockCount());
835 >                readUnlocker.accept(lock, s);
836 >            }
837          }
838      }
839  
840      /**
841 <     * tryConvertToWriteLock succeeds and validates if successfully locked
842 <     * or lock free;
843 <     */
844 <    public void testTryConvertToWriteLock() {
845 <        try {
846 <            StampedLock lock = new StampedLock();
847 <            long s, p;
848 <            s = 0L;
849 <            assertFalse((p = lock.tryConvertToWriteLock(s)) != 0L);
850 <            assertTrue((s = lock.tryOptimisticRead()) != 0L);
851 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
852 <            lock.unlockWrite(p);
853 <            assertTrue((s = lock.writeLock()) != 0L);
854 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
855 <            assertTrue(lock.validate(p));
856 <            lock.unlockWrite(p);
857 <            assertTrue((s = lock.readLock()) != 0L);
858 <            assertTrue(lock.validate(s));
859 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
860 <            assertTrue(lock.validate(p));
861 <            lock.unlockWrite(p);
862 <            assertTrue((s = lock.tryWriteLock()) != 0L);
863 <            assertTrue(lock.validate(s));
864 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
865 <            assertTrue(lock.validate(p));
866 <            lock.unlockWrite(p);
867 <            assertTrue((s = lock.tryReadLock()) != 0L);
868 <            assertTrue(lock.validate(s));
869 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
870 <            assertTrue(lock.validate(p));
871 <            lock.unlockWrite(p);
872 <            assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
873 <            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
874 <            assertTrue(lock.validate(p));
875 <            lock.unlockWrite(p);
876 <            assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
841 >     * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
842 >     */
843 >    public void testTryConvertToWriteLock() throws InterruptedException {
844 >        StampedLock lock = new StampedLock();
845 >        long s, p;
846 >
847 >        assertEquals(0L, lock.tryConvertToWriteLock(0L));
848 >
849 >        assertTrue((s = lock.tryOptimisticRead()) != 0L);
850 >        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
851 >        assertTrue(lock.isWriteLocked());
852 >        lock.unlockWrite(p);
853 >
854 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
855 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
856 >                s = assertValid(lock, writeLocker.apply(lock));
857 >                assertEquals(s, lock.tryConvertToWriteLock(s));
858 >                assertTrue(lock.validate(s));
859 >                assertTrue(lock.isWriteLocked());
860 >                writeUnlocker.accept(lock, s);
861 >            }
862 >
863 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
864 >                s = assertValid(lock, readLocker.apply(lock));
865 >                p = assertValid(lock, lock.tryConvertToWriteLock(s));
866 >                assertFalse(lock.validate(s));
867 >                assertTrue(lock.validate(p));
868 >                assertTrue(lock.isWriteLocked());
869 >                writeUnlocker.accept(lock, p);
870 >            }
871 >        }
872 >
873 >        // failure if multiply read locked
874 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
875 >            s = assertValid(lock, readLocker.apply(lock));
876 >            p = assertValid(lock, readLocker.apply(lock));
877 >            assertEquals(0L, lock.tryConvertToWriteLock(s));
878              assertTrue(lock.validate(s));
879            assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
879              assertTrue(lock.validate(p));
880 <            lock.unlockWrite(p);
881 <        } catch (InterruptedException ie) {
882 <            threadUnexpectedException(ie);
880 >            assertEquals(2, lock.getReadLockCount());
881 >            lock.unlock(p);
882 >            lock.unlock(s);
883 >            assertUnlocked(lock);
884          }
885      }
886  
887      /**
888       * asWriteLock can be locked and unlocked
889       */
890 <    public void testAsWriteLock() {
890 >    public void testAsWriteLock() throws Throwable {
891          StampedLock sl = new StampedLock();
892          Lock lock = sl.asWriteLock();
893 <        lock.lock();
894 <        assertFalse(lock.tryLock());
895 <        lock.unlock();
896 <        assertTrue(lock.tryLock());
893 >        for (Action locker : lockLockers(lock)) {
894 >            locker.run();
895 >            assertTrue(sl.isWriteLocked());
896 >            assertFalse(sl.isReadLocked());
897 >            assertFalse(lock.tryLock());
898 >            lock.unlock();
899 >            assertUnlocked(sl);
900 >        }
901      }
902  
903      /**
904       * asReadLock can be locked and unlocked
905       */
906 <    public void testAsReadLock() {
906 >    public void testAsReadLock() throws Throwable {
907          StampedLock sl = new StampedLock();
908          Lock lock = sl.asReadLock();
909 <        lock.lock();
910 <        lock.unlock();
911 <        assertTrue(lock.tryLock());
909 >        for (Action locker : lockLockers(lock)) {
910 >            locker.run();
911 >            assertTrue(sl.isReadLocked());
912 >            assertFalse(sl.isWriteLocked());
913 >            assertEquals(1, sl.getReadLockCount());
914 >            locker.run();
915 >            assertTrue(sl.isReadLocked());
916 >            assertEquals(2, sl.getReadLockCount());
917 >            lock.unlock();
918 >            lock.unlock();
919 >            assertUnlocked(sl);
920 >        }
921      }
922  
923      /**
924       * asReadWriteLock.writeLock can be locked and unlocked
925       */
926 <    public void testAsReadWriteLockWriteLock() {
926 >    public void testAsReadWriteLockWriteLock() throws Throwable {
927          StampedLock sl = new StampedLock();
928          Lock lock = sl.asReadWriteLock().writeLock();
929 <        lock.lock();
930 <        assertFalse(lock.tryLock());
931 <        lock.unlock();
932 <        assertTrue(lock.tryLock());
929 >        for (Action locker : lockLockers(lock)) {
930 >            locker.run();
931 >            assertTrue(sl.isWriteLocked());
932 >            assertFalse(sl.isReadLocked());
933 >            assertFalse(lock.tryLock());
934 >            lock.unlock();
935 >            assertUnlocked(sl);
936 >        }
937      }
938  
939      /**
940       * asReadWriteLock.readLock can be locked and unlocked
941       */
942 <    public void testAsReadWriteLockReadLock() {
942 >    public void testAsReadWriteLockReadLock() throws Throwable {
943          StampedLock sl = new StampedLock();
944          Lock lock = sl.asReadWriteLock().readLock();
945 <        lock.lock();
946 <        lock.unlock();
947 <        assertTrue(lock.tryLock());
945 >        for (Action locker : lockLockers(lock)) {
946 >            locker.run();
947 >            assertTrue(sl.isReadLocked());
948 >            assertFalse(sl.isWriteLocked());
949 >            assertEquals(1, sl.getReadLockCount());
950 >            locker.run();
951 >            assertTrue(sl.isReadLocked());
952 >            assertEquals(2, sl.getReadLockCount());
953 >            lock.unlock();
954 >            lock.unlock();
955 >            assertUnlocked(sl);
956 >        }
957      }
958  
959 +    /**
960 +     * Lock.newCondition throws UnsupportedOperationException
961 +     */
962 +    public void testLockViewsDoNotSupportConditions() {
963 +        StampedLock sl = new StampedLock();
964 +        assertThrows(UnsupportedOperationException.class,
965 +                     () -> sl.asWriteLock().newCondition(),
966 +                     () -> sl.asReadLock().newCondition(),
967 +                     () -> sl.asReadWriteLock().writeLock().newCondition(),
968 +                     () -> sl.asReadWriteLock().readLock().newCondition());
969 +    }
970 +
971 +    /**
972 +     * Passing optimistic read stamps to unlock operations result in
973 +     * IllegalMonitorStateException
974 +     */
975 +    public void testCannotUnlockOptimisticReadStamps() {
976 +        Runnable[] actions = {
977 +            () -> {
978 +                StampedLock sl = new StampedLock();
979 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
980 +                sl.unlockRead(stamp);
981 +            },
982 +            () -> {
983 +                StampedLock sl = new StampedLock();
984 +                long stamp = sl.tryOptimisticRead();
985 +                sl.unlock(stamp);
986 +            },
987 +
988 +            () -> {
989 +                StampedLock sl = new StampedLock();
990 +                long stamp = sl.tryOptimisticRead();
991 +                sl.writeLock();
992 +                sl.unlock(stamp);
993 +            },
994 +            () -> {
995 +                StampedLock sl = new StampedLock();
996 +                sl.readLock();
997 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
998 +                sl.unlockRead(stamp);
999 +            },
1000 +            () -> {
1001 +                StampedLock sl = new StampedLock();
1002 +                sl.readLock();
1003 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
1004 +                sl.unlock(stamp);
1005 +            },
1006 +
1007 +            () -> {
1008 +                StampedLock sl = new StampedLock();
1009 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1010 +                assertValid(sl, stamp);
1011 +                sl.writeLock();
1012 +                sl.unlockWrite(stamp);
1013 +            },
1014 +            () -> {
1015 +                StampedLock sl = new StampedLock();
1016 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1017 +                sl.writeLock();
1018 +                sl.unlock(stamp);
1019 +            },
1020 +            () -> {
1021 +                StampedLock sl = new StampedLock();
1022 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1023 +                sl.readLock();
1024 +                sl.unlockRead(stamp);
1025 +            },
1026 +            () -> {
1027 +                StampedLock sl = new StampedLock();
1028 +                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1029 +                sl.readLock();
1030 +                sl.unlock(stamp);
1031 +            },
1032 +
1033 +            () -> {
1034 +                StampedLock sl = new StampedLock();
1035 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1036 +                assertValid(sl, stamp);
1037 +                sl.writeLock();
1038 +                sl.unlockWrite(stamp);
1039 +            },
1040 +            () -> {
1041 +                StampedLock sl = new StampedLock();
1042 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1043 +                sl.writeLock();
1044 +                sl.unlock(stamp);
1045 +            },
1046 +            () -> {
1047 +                StampedLock sl = new StampedLock();
1048 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1049 +                sl.readLock();
1050 +                sl.unlockRead(stamp);
1051 +            },
1052 +            () -> {
1053 +                StampedLock sl = new StampedLock();
1054 +                sl.readLock();
1055 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1056 +                assertValid(sl, stamp);
1057 +                sl.readLock();
1058 +                sl.unlockRead(stamp);
1059 +            },
1060 +            () -> {
1061 +                StampedLock sl = new StampedLock();
1062 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1063 +                sl.readLock();
1064 +                sl.unlock(stamp);
1065 +            },
1066 +            () -> {
1067 +                StampedLock sl = new StampedLock();
1068 +                sl.readLock();
1069 +                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1070 +                sl.readLock();
1071 +                sl.unlock(stamp);
1072 +            },
1073 +        };
1074 +
1075 +        assertThrows(IllegalMonitorStateException.class, actions);
1076 +    }
1077 +
1078 +    static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
1079 +        try { return sl.writeLockInterruptibly(); }
1080 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1081 +    }
1082 +
1083 +    static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1084 +        try { return sl.tryWriteLock(time, unit); }
1085 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1086 +    }
1087 +
1088 +    static long readLockInterruptiblyUninterrupted(StampedLock sl) {
1089 +        try { return sl.readLockInterruptibly(); }
1090 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1091 +    }
1092 +
1093 +    static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1094 +        try { return sl.tryReadLock(time, unit); }
1095 +        catch (InterruptedException ex) { throw new AssertionError(ex); }
1096 +    }
1097 +
1098 +    /**
1099 +     * Invalid stamps result in IllegalMonitorStateException
1100 +     */
1101 +    public void testInvalidStampsThrowIllegalMonitorStateException() {
1102 +        final StampedLock sl = new StampedLock();
1103 +
1104 +        assertThrows(IllegalMonitorStateException.class,
1105 +                     () -> sl.unlockWrite(0L),
1106 +                     () -> sl.unlockRead(0L),
1107 +                     () -> sl.unlock(0L));
1108 +
1109 +        final long optimisticStamp = sl.tryOptimisticRead();
1110 +        final long readStamp = sl.readLock();
1111 +        sl.unlockRead(readStamp);
1112 +        final long writeStamp = sl.writeLock();
1113 +        sl.unlockWrite(writeStamp);
1114 +        assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1115 +        final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1116 +        final Runnable assertNoLongerValidStampsThrow = () -> {
1117 +            for (long noLongerValidStamp : noLongerValidStamps)
1118 +                assertThrows(IllegalMonitorStateException.class,
1119 +                             () -> sl.unlockWrite(noLongerValidStamp),
1120 +                             () -> sl.unlockRead(noLongerValidStamp),
1121 +                             () -> sl.unlock(noLongerValidStamp));
1122 +        };
1123 +        assertNoLongerValidStampsThrow.run();
1124 +
1125 +        for (Function<StampedLock, Long> readLocker : readLockers())
1126 +        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1127 +            final long stamp = readLocker.apply(sl);
1128 +            assertValid(sl, stamp);
1129 +            assertNoLongerValidStampsThrow.run();
1130 +            assertThrows(IllegalMonitorStateException.class,
1131 +                         () -> sl.unlockWrite(stamp),
1132 +                         () -> sl.unlockRead(sl.tryOptimisticRead()),
1133 +                         () -> sl.unlockRead(0L));
1134 +            readUnlocker.accept(sl, stamp);
1135 +            assertUnlocked(sl);
1136 +            assertNoLongerValidStampsThrow.run();
1137 +        }
1138 +
1139 +        for (Function<StampedLock, Long> writeLocker : writeLockers())
1140 +        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1141 +            final long stamp = writeLocker.apply(sl);
1142 +            assertValid(sl, stamp);
1143 +            assertNoLongerValidStampsThrow.run();
1144 +            assertThrows(IllegalMonitorStateException.class,
1145 +                         () -> sl.unlockRead(stamp),
1146 +                         () -> sl.unlockWrite(0L));
1147 +            writeUnlocker.accept(sl, stamp);
1148 +            assertUnlocked(sl);
1149 +            assertNoLongerValidStampsThrow.run();
1150 +        }
1151 +    }
1152 +
1153 +    /**
1154 +     * Read locks can be very deeply nested
1155 +     */
1156 +    public void testDeeplyNestedReadLocks() {
1157 +        final StampedLock lock = new StampedLock();
1158 +        final int depth = 300;
1159 +        final long[] stamps = new long[depth];
1160 +        final List<Function<StampedLock, Long>> readLockers = readLockers();
1161 +        final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1162 +        for (int i = 0; i < depth; i++) {
1163 +            Function<StampedLock, Long> readLocker
1164 +                = readLockers.get(i % readLockers.size());
1165 +            long stamp = readLocker.apply(lock);
1166 +            assertEquals(i + 1, lock.getReadLockCount());
1167 +            assertTrue(lock.isReadLocked());
1168 +            stamps[i] = stamp;
1169 +        }
1170 +        for (int i = 0; i < depth; i++) {
1171 +            BiConsumer<StampedLock, Long> readUnlocker
1172 +                = readUnlockers.get(i % readUnlockers.size());
1173 +            assertEquals(depth - i, lock.getReadLockCount());
1174 +            assertTrue(lock.isReadLocked());
1175 +            readUnlocker.accept(lock, stamps[depth - 1 - i]);
1176 +        }
1177 +        assertUnlocked(lock);
1178 +    }
1179   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines