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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines