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.26 by jsr166, Sun Jul 17 03:06:50 2016 UTC vs.
Revision 1.42 by jsr166, Mon Nov 27 23:38:11 2017 UTC

# Line 8 | Line 8
8   import static java.util.concurrent.TimeUnit.DAYS;
9   import static java.util.concurrent.TimeUnit.MILLISECONDS;
10  
11 + import static java.util.concurrent.locks.StampedLock.isLockStamp;
12 + import static java.util.concurrent.locks.StampedLock.isOptimisticReadStamp;
13 + import static java.util.concurrent.locks.StampedLock.isReadLockStamp;
14 + import static java.util.concurrent.locks.StampedLock.isWriteLockStamp;
15 +
16   import java.util.ArrayList;
17   import java.util.List;
18   import java.util.concurrent.CountDownLatch;
19 + import java.util.concurrent.Future;
20   import java.util.concurrent.TimeUnit;
21   import java.util.concurrent.locks.Lock;
22   import java.util.concurrent.locks.StampedLock;
23   import java.util.function.BiConsumer;
18 import java.util.function.Consumer;
24   import java.util.function.Function;
25  
26   import junit.framework.Test;
# Line 30 | Line 35 | public class StampedLockTest extends JSR
35      }
36  
37      /**
33     * A runnable calling writeLockInterruptibly
34     */
35    class InterruptibleLockRunnable extends CheckedRunnable {
36        final StampedLock lock;
37        InterruptibleLockRunnable(StampedLock l) { lock = l; }
38        public void realRun() throws InterruptedException {
39            lock.writeLockInterruptibly();
40        }
41    }
42
43    /**
44     * A runnable calling writeLockInterruptibly that expects to be
45     * interrupted
46     */
47    class InterruptedLockRunnable extends CheckedInterruptedRunnable {
48        final StampedLock lock;
49        InterruptedLockRunnable(StampedLock l) { lock = l; }
50        public void realRun() throws InterruptedException {
51            lock.writeLockInterruptibly();
52        }
53    }
54
55    /**
38       * Releases write lock, checking isWriteLocked before and after
39       */
40 <    void releaseWriteLock(StampedLock lock, long s) {
40 >    void releaseWriteLock(StampedLock lock, long stamp) {
41          assertTrue(lock.isWriteLocked());
42 <        lock.unlockWrite(s);
42 >        assertValid(lock, stamp);
43 >        lock.unlockWrite(stamp);
44          assertFalse(lock.isWriteLocked());
45 +        assertFalse(lock.validate(stamp));
46      }
47  
48      /**
49 <     * Constructed StampedLock is in unlocked state
49 >     * Releases read lock, checking isReadLocked before and after
50       */
51 <    public void testConstructor() {
52 <        StampedLock lock;
53 <        lock = new StampedLock();
54 <        assertFalse(lock.isWriteLocked());
51 >    void releaseReadLock(StampedLock lock, long stamp) {
52 >        assertTrue(lock.isReadLocked());
53 >        assertValid(lock, stamp);
54 >        lock.unlockRead(stamp);
55          assertFalse(lock.isReadLocked());
56 <        assertEquals(lock.getReadLockCount(), 0);
56 >        assertTrue(lock.validate(stamp));
57      }
58  
59 <    /**
60 <     * write-locking and read-locking an unlocked lock succeed
61 <     */
78 <    public void testLock() {
79 <        StampedLock lock = new StampedLock();
80 <        assertFalse(lock.isWriteLocked());
81 <        assertFalse(lock.isReadLocked());
82 <        assertEquals(lock.getReadLockCount(), 0);
83 <        long s = lock.writeLock();
84 <        assertTrue(lock.isWriteLocked());
85 <        assertFalse(lock.isReadLocked());
86 <        assertEquals(lock.getReadLockCount(), 0);
87 <        lock.unlockWrite(s);
88 <        assertFalse(lock.isWriteLocked());
89 <        assertFalse(lock.isReadLocked());
90 <        assertEquals(lock.getReadLockCount(), 0);
91 <        long rs = lock.readLock();
92 <        assertFalse(lock.isWriteLocked());
93 <        assertTrue(lock.isReadLocked());
94 <        assertEquals(lock.getReadLockCount(), 1);
95 <        lock.unlockRead(rs);
96 <        assertFalse(lock.isWriteLocked());
97 <        assertFalse(lock.isReadLocked());
98 <        assertEquals(lock.getReadLockCount(), 0);
59 >    long assertNonZero(long v) {
60 >        assertTrue(v != 0L);
61 >        return v;
62      }
63  
64 <    /**
65 <     * unlock releases either a read or write lock
66 <     */
67 <    public void testUnlock() {
105 <        StampedLock lock = new StampedLock();
106 <        assertFalse(lock.isWriteLocked());
107 <        assertFalse(lock.isReadLocked());
108 <        assertEquals(lock.getReadLockCount(), 0);
109 <        long s = lock.writeLock();
110 <        assertTrue(lock.isWriteLocked());
111 <        assertFalse(lock.isReadLocked());
112 <        assertEquals(lock.getReadLockCount(), 0);
113 <        lock.unlock(s);
114 <        assertFalse(lock.isWriteLocked());
115 <        assertFalse(lock.isReadLocked());
116 <        assertEquals(lock.getReadLockCount(), 0);
117 <        long rs = lock.readLock();
118 <        assertFalse(lock.isWriteLocked());
119 <        assertTrue(lock.isReadLocked());
120 <        assertEquals(lock.getReadLockCount(), 1);
121 <        lock.unlock(rs);
122 <        assertFalse(lock.isWriteLocked());
123 <        assertFalse(lock.isReadLocked());
124 <        assertEquals(lock.getReadLockCount(), 0);
64 >    long assertValid(StampedLock lock, long stamp) {
65 >        assertTrue(stamp != 0L);
66 >        assertTrue(lock.validate(stamp));
67 >        return stamp;
68      }
69  
70 <    /**
128 <     * tryUnlockRead/Write succeeds if locked in associated mode else
129 <     * returns false
130 <     */
131 <    public void testTryUnlock() {
132 <        StampedLock lock = new StampedLock();
133 <        assertFalse(lock.isWriteLocked());
70 >    void assertUnlocked(StampedLock lock) {
71          assertFalse(lock.isReadLocked());
135        assertEquals(lock.getReadLockCount(), 0);
136        long s = lock.writeLock();
137        assertTrue(lock.isWriteLocked());
138        assertFalse(lock.isReadLocked());
139        assertEquals(lock.getReadLockCount(), 0);
140        assertFalse(lock.tryUnlockRead());
141        assertTrue(lock.tryUnlockWrite());
142        assertFalse(lock.tryUnlockWrite());
143        assertFalse(lock.tryUnlockRead());
144        assertFalse(lock.isWriteLocked());
145        assertFalse(lock.isReadLocked());
146        assertEquals(lock.getReadLockCount(), 0);
147        long rs = lock.readLock();
148        assertFalse(lock.isWriteLocked());
149        assertTrue(lock.isReadLocked());
150        assertEquals(lock.getReadLockCount(), 1);
151        assertFalse(lock.tryUnlockWrite());
152        assertTrue(lock.tryUnlockRead());
153        assertFalse(lock.tryUnlockRead());
154        assertFalse(lock.tryUnlockWrite());
72          assertFalse(lock.isWriteLocked());
73 <        assertFalse(lock.isReadLocked());
74 <        assertEquals(lock.getReadLockCount(), 0);
73 >        assertEquals(0, lock.getReadLockCount());
74 >        assertValid(lock, lock.tryOptimisticRead());
75      }
76  
77 <    /**
78 <     * write-unlocking an unlocked lock throws IllegalMonitorStateException
79 <     */
80 <    public void testWriteUnlock_IMSE() {
81 <        StampedLock lock = new StampedLock();
82 <        try {
83 <            lock.unlockWrite(0L);
84 <            shouldThrow();
85 <        } catch (IllegalMonitorStateException success) {}
77 >    List<Action> lockLockers(Lock lock) {
78 >        List<Action> lockers = new ArrayList<>();
79 >        lockers.add(() -> lock.lock());
80 >        lockers.add(() -> lock.lockInterruptibly());
81 >        lockers.add(() -> lock.tryLock());
82 >        lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS));
83 >        lockers.add(() -> lock.tryLock(0L, DAYS));
84 >        lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS));
85 >        return lockers;
86 >    }
87 >
88 >    List<Function<StampedLock, Long>> readLockers() {
89 >        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
90 >        readLockers.add(sl -> sl.readLock());
91 >        readLockers.add(sl -> sl.tryReadLock());
92 >        readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
93 >        readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
94 >        readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
95 >        readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
96 >        return readLockers;
97 >    }
98 >
99 >    List<BiConsumer<StampedLock, Long>> readUnlockers() {
100 >        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
101 >        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
102 >        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
103 >        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
104 >        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
105 >        readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
106 >        return readUnlockers;
107 >    }
108 >
109 >    List<Function<StampedLock, Long>> writeLockers() {
110 >        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
111 >        writeLockers.add(sl -> sl.writeLock());
112 >        writeLockers.add(sl -> sl.tryWriteLock());
113 >        writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
114 >        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
115 >        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
116 >        writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
117 >        return writeLockers;
118 >    }
119 >
120 >    List<BiConsumer<StampedLock, Long>> writeUnlockers() {
121 >        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
122 >        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
123 >        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
124 >        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
125 >        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
126 >        writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
127 >        return writeUnlockers;
128      }
129  
130      /**
131 <     * write-unlocking an unlocked lock throws IllegalMonitorStateException
131 >     * Constructed StampedLock is in unlocked state
132       */
133 <    public void testWriteUnlock_IMSE2() {
134 <        StampedLock lock = new StampedLock();
176 <        long s = lock.writeLock();
177 <        lock.unlockWrite(s);
178 <        try {
179 <            lock.unlockWrite(s);
180 <            shouldThrow();
181 <        } catch (IllegalMonitorStateException success) {}
133 >    public void testConstructor() {
134 >        assertUnlocked(new StampedLock());
135      }
136  
137      /**
138 <     * write-unlocking after readlock throws IllegalMonitorStateException
138 >     * write-locking, then unlocking, an unlocked lock succeed
139       */
140 <    public void testWriteUnlock_IMSE3() {
140 >    public void testWriteLock_lockUnlock() {
141          StampedLock lock = new StampedLock();
142 <        long s = lock.readLock();
143 <        try {
144 <            lock.unlockWrite(s);
145 <            shouldThrow();
146 <        } catch (IllegalMonitorStateException success) {}
142 >
143 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
144 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
145 >            assertFalse(lock.isWriteLocked());
146 >            assertFalse(lock.isReadLocked());
147 >            assertEquals(0, lock.getReadLockCount());
148 >
149 >            long s = writeLocker.apply(lock);
150 >            assertValid(lock, s);
151 >            assertTrue(lock.isWriteLocked());
152 >            assertFalse(lock.isReadLocked());
153 >            assertEquals(0, lock.getReadLockCount());
154 >            writeUnlocker.accept(lock, s);
155 >            assertUnlocked(lock);
156 >        }
157      }
158  
159      /**
160 <     * read-unlocking an unlocked lock throws IllegalMonitorStateException
160 >     * read-locking, then unlocking, an unlocked lock succeed
161       */
162 <    public void testReadUnlock_IMSE() {
162 >    public void testReadLock_lockUnlock() {
163          StampedLock lock = new StampedLock();
164 <        long s = lock.readLock();
165 <        lock.unlockRead(s);
166 <        try {
167 <            lock.unlockRead(s);
168 <            shouldThrow();
169 <        } catch (IllegalMonitorStateException success) {}
164 >
165 >        for (Function<StampedLock, Long> readLocker : readLockers())
166 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
167 >            long s = 42;
168 >            for (int i = 0; i < 2; i++) {
169 >                s = assertValid(lock, readLocker.apply(lock));
170 >                assertFalse(lock.isWriteLocked());
171 >                assertTrue(lock.isReadLocked());
172 >                assertEquals(i + 1, lock.getReadLockCount());
173 >            }
174 >            for (int i = 0; i < 2; i++) {
175 >                assertFalse(lock.isWriteLocked());
176 >                assertTrue(lock.isReadLocked());
177 >                assertEquals(2 - i, lock.getReadLockCount());
178 >                readUnlocker.accept(lock, s);
179 >            }
180 >            assertUnlocked(lock);
181 >        }
182      }
183  
184      /**
185 <     * read-unlocking an unlocked lock throws IllegalMonitorStateException
185 >     * tryUnlockWrite fails if not write locked
186       */
187 <    public void testReadUnlock_IMSE2() {
187 >    public void testTryUnlockWrite_failure() {
188          StampedLock lock = new StampedLock();
189 <        try {
190 <            lock.unlockRead(0L);
191 <            shouldThrow();
192 <        } catch (IllegalMonitorStateException success) {}
189 >        assertFalse(lock.tryUnlockWrite());
190 >
191 >        for (Function<StampedLock, Long> readLocker : readLockers())
192 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
193 >            long s = assertValid(lock, readLocker.apply(lock));
194 >            assertFalse(lock.tryUnlockWrite());
195 >            assertTrue(lock.isReadLocked());
196 >            readUnlocker.accept(lock, s);
197 >            assertUnlocked(lock);
198 >        }
199      }
200  
201      /**
202 <     * read-unlocking after writeLock throws IllegalMonitorStateException
202 >     * tryUnlockRead fails if not read locked
203       */
204 <    public void testReadUnlock_IMSE3() {
204 >    public void testTryUnlockRead_failure() {
205          StampedLock lock = new StampedLock();
206 <        long s = lock.writeLock();
207 <        try {
208 <            lock.unlockRead(s);
209 <            shouldThrow();
210 <        } catch (IllegalMonitorStateException success) {}
206 >        assertFalse(lock.tryUnlockRead());
207 >
208 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
209 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
210 >            long s = writeLocker.apply(lock);
211 >            assertFalse(lock.tryUnlockRead());
212 >            assertTrue(lock.isWriteLocked());
213 >            writeUnlocker.accept(lock, s);
214 >            assertUnlocked(lock);
215 >        }
216      }
217  
218      /**
219 <     * validate(0) fails
219 >     * validate(0L) fails
220       */
221      public void testValidate0() {
222          StampedLock lock = new StampedLock();
# Line 238 | Line 224 | public class StampedLockTest extends JSR
224      }
225  
226      /**
227 <     * A stamp obtained from a successful lock operation validates
227 >     * A stamp obtained from a successful lock operation validates while the lock is held
228       */
229      public void testValidate() throws InterruptedException {
230          StampedLock lock = new StampedLock();
231 <        long s = lock.writeLock();
232 <        assertTrue(lock.validate(s));
233 <        lock.unlockWrite(s);
234 <        s = lock.readLock();
235 <        assertTrue(lock.validate(s));
236 <        lock.unlockRead(s);
237 <        assertTrue((s = lock.tryWriteLock()) != 0L);
238 <        assertTrue(lock.validate(s));
239 <        lock.unlockWrite(s);
240 <        assertTrue((s = lock.tryReadLock()) != 0L);
241 <        assertTrue(lock.validate(s));
242 <        lock.unlockRead(s);
243 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
244 <        assertTrue(lock.validate(s));
259 <        lock.unlockWrite(s);
260 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
261 <        assertTrue(lock.validate(s));
262 <        lock.unlockRead(s);
263 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
231 >
232 >        for (Function<StampedLock, Long> readLocker : readLockers())
233 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
234 >            long s = assertNonZero(readLocker.apply(lock));
235 >            assertTrue(lock.validate(s));
236 >            readUnlocker.accept(lock, s);
237 >        }
238 >
239 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
240 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
241 >            long s = assertNonZero(writeLocker.apply(lock));
242 >            assertTrue(lock.validate(s));
243 >            writeUnlocker.accept(lock, s);
244 >        }
245      }
246  
247      /**
# Line 268 | Line 249 | public class StampedLockTest extends JSR
249       */
250      public void testValidate2() throws InterruptedException {
251          StampedLock lock = new StampedLock();
252 <        long s;
272 <        assertTrue((s = lock.writeLock()) != 0L);
252 >        long s = assertNonZero(lock.writeLock());
253          assertTrue(lock.validate(s));
254          assertFalse(lock.validate(lock.tryWriteLock()));
255 <        assertFalse(lock.validate(lock.tryWriteLock(10L, MILLISECONDS)));
255 >        assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(),
256 >                                                    randomTimeUnit())));
257          assertFalse(lock.validate(lock.tryReadLock()));
258 <        assertFalse(lock.validate(lock.tryReadLock(10L, MILLISECONDS)));
258 >        assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(),
259 >                                                    randomTimeUnit())));
260          assertFalse(lock.validate(lock.tryOptimisticRead()));
261          lock.unlockWrite(s);
262      }
263  
264 +    void assertThrowInterruptedExceptionWhenPreInterrupted(Action[] actions) {
265 +        for (Action action : actions) {
266 +            Thread.currentThread().interrupt();
267 +            try {
268 +                action.run();
269 +                shouldThrow();
270 +            }
271 +            catch (InterruptedException success) {}
272 +            catch (Throwable fail) { threadUnexpectedException(fail); }
273 +            assertFalse(Thread.interrupted());
274 +        }
275 +    }
276 +
277      /**
278 <     * writeLockInterruptibly is interruptible
278 >     * interruptible operations throw InterruptedException when pre-interrupted
279       */
280 <    public void testWriteLockInterruptibly_Interruptible()
286 <            throws InterruptedException {
287 <        final CountDownLatch running = new CountDownLatch(1);
280 >    public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() {
281          final StampedLock lock = new StampedLock();
289        long s = lock.writeLock();
290        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
291            public void realRun() throws InterruptedException {
292                running.countDown();
293                lock.writeLockInterruptibly();
294            }});
282  
283 <        running.await();
284 <        waitForThreadToEnterWaitState(t, 100);
285 <        t.interrupt();
286 <        awaitTermination(t);
287 <        releaseWriteLock(lock, s);
283 >        Action[] interruptibleLockActions = {
284 >            () -> lock.writeLockInterruptibly(),
285 >            () -> lock.tryWriteLock(Long.MIN_VALUE, DAYS),
286 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
287 >            () -> lock.readLockInterruptibly(),
288 >            () -> lock.tryReadLock(Long.MIN_VALUE, DAYS),
289 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
290 >            () -> lock.asWriteLock().lockInterruptibly(),
291 >            () -> lock.asWriteLock().tryLock(0L, DAYS),
292 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
293 >            () -> lock.asReadLock().lockInterruptibly(),
294 >            () -> lock.asReadLock().tryLock(0L, DAYS),
295 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
296 >        };
297 >        shuffle(interruptibleLockActions);
298 >
299 >        assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
300 >        {
301 >            long s = lock.writeLock();
302 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
303 >            lock.unlockWrite(s);
304 >        }
305 >        {
306 >            long s = lock.readLock();
307 >            assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions);
308 >            lock.unlockRead(s);
309 >        }
310 >    }
311 >
312 >    void assertThrowInterruptedExceptionWhenInterrupted(Action[] actions) {
313 >        int n = actions.length;
314 >        Future<?>[] futures = new Future<?>[n];
315 >        CountDownLatch threadsStarted = new CountDownLatch(n);
316 >        CountDownLatch done = new CountDownLatch(n);
317 >
318 >        for (int i = 0; i < n; i++) {
319 >            Action action = actions[i];
320 >            futures[i] = cachedThreadPool.submit(new CheckedRunnable() {
321 >                public void realRun() throws Throwable {
322 >                    threadsStarted.countDown();
323 >                    try {
324 >                        action.run();
325 >                        shouldThrow();
326 >                    }
327 >                    catch (InterruptedException success) {}
328 >                    catch (Throwable fail) { threadUnexpectedException(fail); }
329 >                    assertFalse(Thread.interrupted());
330 >                    done.countDown();
331 >                }});
332 >        }
333 >
334 >        await(threadsStarted);
335 >        assertEquals(n, done.getCount());
336 >        for (Future<?> future : futures) // Interrupt all the tasks
337 >            future.cancel(true);
338 >        await(done);
339      }
340  
341      /**
342 <     * timed tryWriteLock is interruptible
342 >     * interruptible operations throw InterruptedException when write locked and interrupted
343       */
344 <    public void testWriteTryLock_Interruptible() throws InterruptedException {
307 <        final CountDownLatch running = new CountDownLatch(1);
344 >    public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
345          final StampedLock lock = new StampedLock();
346          long s = lock.writeLock();
310        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
311            public void realRun() throws InterruptedException {
312                running.countDown();
313                lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS);
314            }});
347  
348 <        running.await();
349 <        waitForThreadToEnterWaitState(t, 100);
350 <        t.interrupt();
351 <        awaitTermination(t);
352 <        releaseWriteLock(lock, s);
348 >        Action[] interruptibleLockBlockingActions = {
349 >            () -> lock.writeLockInterruptibly(),
350 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
351 >            () -> lock.readLockInterruptibly(),
352 >            () -> lock.tryReadLock(Long.MAX_VALUE, DAYS),
353 >            () -> lock.asWriteLock().lockInterruptibly(),
354 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
355 >            () -> lock.asReadLock().lockInterruptibly(),
356 >            () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS),
357 >        };
358 >        shuffle(interruptibleLockBlockingActions);
359 >
360 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
361      }
362  
363      /**
364 <     * readLockInterruptibly is interruptible
364 >     * interruptible operations throw InterruptedException when read locked and interrupted
365       */
366 <    public void testReadLockInterruptibly_Interruptible()
327 <            throws InterruptedException {
328 <        final CountDownLatch running = new CountDownLatch(1);
366 >    public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
367          final StampedLock lock = new StampedLock();
368 <        long s = lock.writeLock();
331 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
332 <            public void realRun() throws InterruptedException {
333 <                running.countDown();
334 <                lock.readLockInterruptibly();
335 <            }});
368 >        long s = lock.readLock();
369  
370 <        running.await();
371 <        waitForThreadToEnterWaitState(t, 100);
372 <        t.interrupt();
373 <        awaitTermination(t);
374 <        releaseWriteLock(lock, s);
370 >        Action[] interruptibleLockBlockingActions = {
371 >            () -> lock.writeLockInterruptibly(),
372 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
373 >            () -> lock.asWriteLock().lockInterruptibly(),
374 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
375 >        };
376 >        shuffle(interruptibleLockBlockingActions);
377 >
378 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
379      }
380  
381      /**
382 <     * timed tryReadLock is interruptible
382 >     * Non-interruptible operations ignore and preserve interrupt status
383       */
384 <    public void testReadTryLock_Interruptible() throws InterruptedException {
348 <        final CountDownLatch running = new CountDownLatch(1);
384 >    public void testNonInterruptibleOperationsIgnoreInterrupts() {
385          final StampedLock lock = new StampedLock();
386 <        long s = lock.writeLock();
351 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
352 <            public void realRun() throws InterruptedException {
353 <                running.countDown();
354 <                lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS);
355 <            }});
386 >        Thread.currentThread().interrupt();
387  
388 <        running.await();
389 <        waitForThreadToEnterWaitState(t, 100);
390 <        t.interrupt();
391 <        awaitTermination(t);
392 <        releaseWriteLock(lock, s);
388 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
389 >            long s = assertValid(lock, lock.readLock());
390 >            readUnlocker.accept(lock, s);
391 >            s = assertValid(lock, lock.tryReadLock());
392 >            readUnlocker.accept(lock, s);
393 >        }
394 >
395 >        lock.asReadLock().lock();
396 >        lock.asReadLock().unlock();
397 >
398 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
399 >            long s = assertValid(lock, lock.writeLock());
400 >            writeUnlocker.accept(lock, s);
401 >            s = assertValid(lock, lock.tryWriteLock());
402 >            writeUnlocker.accept(lock, s);
403 >        }
404 >
405 >        lock.asWriteLock().lock();
406 >        lock.asWriteLock().unlock();
407 >
408 >        assertTrue(Thread.interrupted());
409      }
410  
411      /**
412       * tryWriteLock on an unlocked lock succeeds
413       */
414 <    public void testWriteTryLock() {
414 >    public void testTryWriteLock() {
415          final StampedLock lock = new StampedLock();
416          long s = lock.tryWriteLock();
417          assertTrue(s != 0L);
418          assertTrue(lock.isWriteLocked());
419 <        long s2 = lock.tryWriteLock();
373 <        assertEquals(s2, 0L);
419 >        assertEquals(0L, lock.tryWriteLock());
420          releaseWriteLock(lock, s);
421      }
422  
423      /**
424       * tryWriteLock fails if locked
425       */
426 <    public void testWriteTryLockWhenLocked() {
426 >    public void testTryWriteLockWhenLocked() {
427          final StampedLock lock = new StampedLock();
428          long s = lock.writeLock();
429          Thread t = newStartedThread(new CheckedRunnable() {
430              public void realRun() {
431 <                long ws = lock.tryWriteLock();
386 <                assertTrue(ws == 0L);
431 >                assertEquals(0L, lock.tryWriteLock());
432              }});
433  
434 +        assertEquals(0L, lock.tryWriteLock());
435          awaitTermination(t);
436          releaseWriteLock(lock, s);
437      }
# Line 393 | Line 439 | public class StampedLockTest extends JSR
439      /**
440       * tryReadLock fails if write-locked
441       */
442 <    public void testReadTryLockWhenLocked() {
442 >    public void testTryReadLockWhenLocked() {
443          final StampedLock lock = new StampedLock();
444          long s = lock.writeLock();
445          Thread t = newStartedThread(new CheckedRunnable() {
446              public void realRun() {
447 <                long rs = lock.tryReadLock();
402 <                assertEquals(rs, 0L);
447 >                assertEquals(0L, lock.tryReadLock());
448              }});
449  
450 +        assertEquals(0L, lock.tryReadLock());
451          awaitTermination(t);
452          releaseWriteLock(lock, s);
453      }
# Line 415 | Line 461 | public class StampedLockTest extends JSR
461          Thread t = newStartedThread(new CheckedRunnable() {
462              public void realRun() throws InterruptedException {
463                  long s2 = lock.tryReadLock();
464 <                assertTrue(s2 != 0L);
464 >                assertValid(lock, s2);
465                  lock.unlockRead(s2);
466                  long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
467 <                assertTrue(s3 != 0L);
467 >                assertValid(lock, s3);
468                  lock.unlockRead(s3);
469                  long s4 = lock.readLock();
470 +                assertValid(lock, s4);
471                  lock.unlockRead(s4);
472 +                lock.asReadLock().lock();
473 +                lock.asReadLock().unlock();
474 +                lock.asReadLock().lockInterruptibly();
475 +                lock.asReadLock().unlock();
476 +                lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
477 +                lock.asReadLock().unlock();
478              }});
479  
480          awaitTermination(t);
# Line 429 | Line 482 | public class StampedLockTest extends JSR
482      }
483  
484      /**
485 <     * A writelock succeeds only after a reading thread unlocks
485 >     * writeLock() succeeds only after a reading thread unlocks
486       */
487      public void testWriteAfterReadLock() throws InterruptedException {
488 <        final CountDownLatch running = new CountDownLatch(1);
488 >        final CountDownLatch aboutToLock = new CountDownLatch(1);
489          final StampedLock lock = new StampedLock();
490          long rs = lock.readLock();
491          Thread t = newStartedThread(new CheckedRunnable() {
492              public void realRun() {
493 <                running.countDown();
493 >                aboutToLock.countDown();
494                  long s = lock.writeLock();
495 +                assertTrue(lock.isWriteLocked());
496 +                assertFalse(lock.isReadLocked());
497                  lock.unlockWrite(s);
498              }});
499  
500 <        running.await();
501 <        waitForThreadToEnterWaitState(t, 100);
500 >        await(aboutToLock);
501 >        assertThreadBlocks(t, Thread.State.WAITING);
502          assertFalse(lock.isWriteLocked());
503 +        assertTrue(lock.isReadLocked());
504          lock.unlockRead(rs);
505          awaitTermination(t);
506 <        assertFalse(lock.isWriteLocked());
506 >        assertUnlocked(lock);
507      }
508  
509      /**
510 <     * A writelock succeeds only after reading threads unlock
510 >     * writeLock() succeeds only after reading threads unlock
511       */
512      public void testWriteAfterMultipleReadLocks() {
513          final StampedLock lock = new StampedLock();
# Line 470 | Line 526 | public class StampedLockTest extends JSR
526                  lock.unlockWrite(ws);
527              }});
528  
529 +        assertTrue(lock.isReadLocked());
530          assertFalse(lock.isWriteLocked());
531          lock.unlockRead(s);
532          awaitTermination(t2);
533 <        assertFalse(lock.isWriteLocked());
533 >        assertUnlocked(lock);
534      }
535  
536      /**
537 <     * Readlocks succeed only after a writing thread unlocks
537 >     * readLock() succeed only after a writing thread unlocks
538       */
539      public void testReadAfterWriteLock() {
540          final StampedLock lock = new StampedLock();
541 +        final CountDownLatch threadsStarted = new CountDownLatch(2);
542          final long s = lock.writeLock();
543 <        Thread t1 = newStartedThread(new CheckedRunnable() {
543 >        final Runnable acquireReleaseReadLock = new CheckedRunnable() {
544              public void realRun() {
545 +                threadsStarted.countDown();
546                  long rs = lock.readLock();
547 +                assertTrue(lock.isReadLocked());
548 +                assertFalse(lock.isWriteLocked());
549                  lock.unlockRead(rs);
550 <            }});
551 <        Thread t2 = newStartedThread(new CheckedRunnable() {
552 <            public void realRun() {
553 <                long rs = lock.readLock();
554 <                lock.unlockRead(rs);
555 <            }});
556 <
550 >            }};
551 >        Thread t1 = newStartedThread(acquireReleaseReadLock);
552 >        Thread t2 = newStartedThread(acquireReleaseReadLock);
553 >
554 >        await(threadsStarted);
555 >        assertThreadBlocks(t1, Thread.State.WAITING);
556 >        assertThreadBlocks(t2, Thread.State.WAITING);
557 >        assertTrue(lock.isWriteLocked());
558 >        assertFalse(lock.isReadLocked());
559          releaseWriteLock(lock, s);
560          awaitTermination(t1);
561          awaitTermination(t2);
562 +        assertUnlocked(lock);
563      }
564  
565      /**
566 <     * tryReadLock succeeds if readlocked but not writelocked
566 >     * tryReadLock succeeds if read locked but not write locked
567       */
568      public void testTryLockWhenReadLocked() {
569          final StampedLock lock = new StampedLock();
# Line 507 | Line 571 | public class StampedLockTest extends JSR
571          Thread t = newStartedThread(new CheckedRunnable() {
572              public void realRun() {
573                  long rs = lock.tryReadLock();
574 <                threadAssertTrue(rs != 0L);
574 >                assertValid(lock, rs);
575                  lock.unlockRead(rs);
576              }});
577  
# Line 516 | Line 580 | public class StampedLockTest extends JSR
580      }
581  
582      /**
583 <     * tryWriteLock fails when readlocked
583 >     * tryWriteLock fails when read locked
584       */
585 <    public void testWriteTryLockWhenReadLocked() {
585 >    public void testTryWriteLockWhenReadLocked() {
586          final StampedLock lock = new StampedLock();
587          long s = lock.readLock();
588          Thread t = newStartedThread(new CheckedRunnable() {
589              public void realRun() {
590 <                long ws = lock.tryWriteLock();
527 <                threadAssertEquals(ws, 0L);
590 >                assertEquals(0L, lock.tryWriteLock());
591              }});
592  
593          awaitTermination(t);
# Line 532 | Line 595 | public class StampedLockTest extends JSR
595      }
596  
597      /**
598 <     * timed tryWriteLock times out if locked
598 >     * timed lock operations time out if lock not available
599       */
600 <    public void testWriteTryLock_Timeout() {
600 >    public void testTimedLock_Timeout() throws Exception {
601 >        ArrayList<Future<?>> futures = new ArrayList<>();
602 >
603 >        // Write locked
604          final StampedLock lock = new StampedLock();
605 <        long s = lock.writeLock();
606 <        Thread t = newStartedThread(new CheckedRunnable() {
605 >        long stamp = lock.writeLock();
606 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
607 >        assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
608 >        assertFalse(lock.asReadLock().tryLock(0L, DAYS));
609 >        assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
610 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
611 >        assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
612 >        assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
613 >        assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
614 >
615 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
616              public void realRun() throws InterruptedException {
617                  long startTime = System.nanoTime();
618 <                long timeoutMillis = 10;
619 <                long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
620 <                assertEquals(ws, 0L);
546 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
547 <            }});
618 >                assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
619 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
620 >            }}));
621  
622 <        awaitTermination(t);
623 <        releaseWriteLock(lock, s);
624 <    }
622 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
623 >            public void realRun() throws InterruptedException {
624 >                long startTime = System.nanoTime();
625 >                assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
626 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
627 >            }}));
628 >
629 >        // Read locked
630 >        final StampedLock lock2 = new StampedLock();
631 >        long stamp2 = lock2.readLock();
632 >        assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
633 >        assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
634 >        assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
635 >        assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
636  
637 <    /**
554 <     * timed tryReadLock times out if write-locked
555 <     */
556 <    public void testReadTryLock_Timeout() {
557 <        final StampedLock lock = new StampedLock();
558 <        long s = lock.writeLock();
559 <        Thread t = newStartedThread(new CheckedRunnable() {
637 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
638              public void realRun() throws InterruptedException {
639                  long startTime = System.nanoTime();
640 <                long timeoutMillis = 10;
641 <                long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
642 <                assertEquals(rs, 0L);
565 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
566 <            }});
640 >                assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
641 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
642 >            }}));
643  
644 <        awaitTermination(t);
645 <        assertTrue(lock.isWriteLocked());
646 <        lock.unlockWrite(s);
644 >        for (Future<?> future : futures)
645 >            assertNull(future.get());
646 >
647 >        releaseWriteLock(lock, stamp);
648 >        releaseReadLock(lock2, stamp2);
649      }
650  
651      /**
652 <     * writeLockInterruptibly succeeds if unlocked, else is interruptible
652 >     * writeLockInterruptibly succeeds if unlocked
653       */
654      public void testWriteLockInterruptibly() throws InterruptedException {
577        final CountDownLatch running = new CountDownLatch(1);
655          final StampedLock lock = new StampedLock();
656          long s = lock.writeLockInterruptibly();
580        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
581            public void realRun() throws InterruptedException {
582                running.countDown();
583                lock.writeLockInterruptibly();
584            }});
585
586        running.await();
587        waitForThreadToEnterWaitState(t, 100);
588        t.interrupt();
657          assertTrue(lock.isWriteLocked());
590        awaitTermination(t);
658          releaseWriteLock(lock, s);
659      }
660  
661      /**
662 <     * readLockInterruptibly succeeds if lock free else is interruptible
662 >     * readLockInterruptibly succeeds if lock free
663       */
664      public void testReadLockInterruptibly() throws InterruptedException {
598        final CountDownLatch running = new CountDownLatch(1);
665          final StampedLock lock = new StampedLock();
666 <        long s;
667 <        s = lock.readLockInterruptibly();
666 >
667 >        long s = assertValid(lock, lock.readLockInterruptibly());
668 >        assertTrue(lock.isReadLocked());
669          lock.unlockRead(s);
603        s = lock.writeLockInterruptibly();
604        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
605            public void realRun() throws InterruptedException {
606                running.countDown();
607                lock.readLockInterruptibly();
608            }});
670  
671 <        running.await();
672 <        waitForThreadToEnterWaitState(t, 100);
673 <        t.interrupt();
613 <        awaitTermination(t);
614 <        releaseWriteLock(lock, s);
671 >        lock.asReadLock().lockInterruptibly();
672 >        assertTrue(lock.isReadLocked());
673 >        lock.asReadLock().unlock();
674      }
675  
676      /**
# Line 643 | Line 702 | public class StampedLockTest extends JSR
702      }
703  
704      /**
705 <     * tryOptimisticRead succeeds and validates if unlocked, fails if locked
705 >     * tryOptimisticRead succeeds and validates if unlocked, fails if
706 >     * exclusively locked
707       */
708      public void testValidateOptimistic() throws InterruptedException {
709          StampedLock lock = new StampedLock();
710 <        long s, p;
711 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
712 <        assertTrue(lock.validate(p));
713 <        assertTrue((s = lock.writeLock()) != 0L);
714 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
715 <        assertTrue(lock.validate(s));
716 <        lock.unlockWrite(s);
717 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
718 <        assertTrue(lock.validate(p));
719 <        assertTrue((s = lock.readLock()) != 0L);
720 <        assertTrue(lock.validate(s));
721 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
722 <        assertTrue(lock.validate(p));
723 <        lock.unlockRead(s);
724 <        assertTrue((s = lock.tryWriteLock()) != 0L);
725 <        assertTrue(lock.validate(s));
726 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
667 <        lock.unlockWrite(s);
668 <        assertTrue((s = lock.tryReadLock()) != 0L);
669 <        assertTrue(lock.validate(s));
670 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
671 <        lock.unlockRead(s);
672 <        assertTrue(lock.validate(p));
673 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
674 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
675 <        assertTrue(lock.validate(s));
676 <        lock.unlockWrite(s);
677 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
678 <        assertTrue(lock.validate(s));
679 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
680 <        lock.unlockRead(s);
681 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
710 >
711 >        assertValid(lock, lock.tryOptimisticRead());
712 >
713 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
714 >            long s = assertValid(lock, writeLocker.apply(lock));
715 >            assertEquals(0L, lock.tryOptimisticRead());
716 >            releaseWriteLock(lock, s);
717 >        }
718 >
719 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
720 >            long s = assertValid(lock, readLocker.apply(lock));
721 >            long p = assertValid(lock, lock.tryOptimisticRead());
722 >            releaseReadLock(lock, s);
723 >            assertTrue(lock.validate(p));
724 >        }
725 >
726 >        assertValid(lock, lock.tryOptimisticRead());
727      }
728  
729      /**
730       * tryOptimisticRead stamp does not validate if a write lock intervenes
731       */
732      public void testValidateOptimisticWriteLocked() {
733 <        StampedLock lock = new StampedLock();
734 <        long s, p;
735 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
691 <        assertTrue((s = lock.writeLock()) != 0L);
733 >        final StampedLock lock = new StampedLock();
734 >        final long p = assertValid(lock, lock.tryOptimisticRead());
735 >        final long s = assertValid(lock, lock.writeLock());
736          assertFalse(lock.validate(p));
737 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
737 >        assertEquals(0L, lock.tryOptimisticRead());
738          assertTrue(lock.validate(s));
739          lock.unlockWrite(s);
740      }
# Line 701 | Line 745 | public class StampedLockTest extends JSR
745       */
746      public void testValidateOptimisticWriteLocked2()
747              throws InterruptedException {
748 <        final CountDownLatch running = new CountDownLatch(1);
748 >        final CountDownLatch locked = new CountDownLatch(1);
749          final StampedLock lock = new StampedLock();
750 <        long s, p;
751 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
750 >        final long p = assertValid(lock, lock.tryOptimisticRead());
751 >
752          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
753              public void realRun() throws InterruptedException {
754                  lock.writeLockInterruptibly();
755 <                running.countDown();
755 >                locked.countDown();
756                  lock.writeLockInterruptibly();
757              }});
758  
759 <        running.await();
759 >        await(locked);
760          assertFalse(lock.validate(p));
761 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
761 >        assertEquals(0L, lock.tryOptimisticRead());
762 >        assertThreadBlocks(t, Thread.State.WAITING);
763          t.interrupt();
764          awaitTermination(t);
765 +        assertTrue(lock.isWriteLocked());
766      }
767  
768      /**
769 <     * tryConvertToOptimisticRead succeeds and validates if successfully locked,
769 >     * tryConvertToOptimisticRead succeeds and validates if successfully locked
770       */
771      public void testTryConvertToOptimisticRead() throws InterruptedException {
772          StampedLock lock = new StampedLock();
773 <        long s, p;
773 >        long s, p, q;
774          assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
775  
776 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
731 <        assertEquals(s, lock.tryConvertToOptimisticRead(s));
732 <        assertTrue(lock.validate(s));
733 <
734 <        assertTrue((p = lock.readLock()) != 0L);
735 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
776 >        s = assertValid(lock, lock.tryOptimisticRead());
777          assertEquals(s, lock.tryConvertToOptimisticRead(s));
778          assertTrue(lock.validate(s));
738        lock.unlockRead(p);
739
740        assertTrue((s = lock.writeLock()) != 0L);
741        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
742        assertTrue(lock.validate(p));
743
744        assertTrue((s = lock.readLock()) != 0L);
745        assertTrue(lock.validate(s));
746        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
747        assertTrue(lock.validate(p));
748
749        assertTrue((s = lock.tryWriteLock()) != 0L);
750        assertTrue(lock.validate(s));
751        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
752        assertTrue(lock.validate(p));
753
754        assertTrue((s = lock.tryReadLock()) != 0L);
755        assertTrue(lock.validate(s));
756        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
757        assertTrue(lock.validate(p));
779  
780 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
781 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
782 <        assertTrue(lock.validate(p));
780 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
781 >            s = assertValid(lock, writeLocker.apply(lock));
782 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
783 >            assertFalse(lock.validate(s));
784 >            assertTrue(lock.validate(p));
785 >            assertUnlocked(lock);
786 >        }
787  
788 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
789 <        assertTrue(lock.validate(s));
790 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
791 <        assertTrue(lock.validate(p));
788 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
789 >            s = assertValid(lock, readLocker.apply(lock));
790 >            q = assertValid(lock, lock.tryOptimisticRead());
791 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
792 >            assertTrue(lock.validate(q));
793 >            assertTrue(lock.isReadLocked());
794 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
795 >            assertTrue(lock.validate(p));
796 >            assertTrue(lock.validate(s));
797 >            assertUnlocked(lock);
798 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
799 >            assertTrue(lock.validate(q));
800 >        }
801      }
802  
803      /**
804 <     * tryConvertToReadLock succeeds and validates if successfully locked
771 <     * or lock free;
804 >     * tryConvertToReadLock succeeds for valid stamps
805       */
806      public void testTryConvertToReadLock() throws InterruptedException {
807          StampedLock lock = new StampedLock();
808          long s, p;
809  
810 <        assertFalse((p = lock.tryConvertToReadLock(0L)) != 0L);
810 >        assertEquals(0L, lock.tryConvertToReadLock(0L));
811  
812 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
813 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
812 >        s = assertValid(lock, lock.tryOptimisticRead());
813 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
814          assertTrue(lock.isReadLocked());
815          assertEquals(1, lock.getReadLockCount());
816 +        assertTrue(lock.validate(s));
817          lock.unlockRead(p);
818  
819 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
819 >        s = assertValid(lock, lock.tryOptimisticRead());
820          lock.readLock();
821 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
821 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
822          assertTrue(lock.isReadLocked());
823          assertEquals(2, lock.getReadLockCount());
824          lock.unlockRead(p);
825          lock.unlockRead(p);
826 +        assertUnlocked(lock);
827  
828 <        assertTrue((s = lock.writeLock()) != 0L);
829 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
830 <        assertTrue(lock.validate(p));
831 <        assertTrue(lock.isReadLocked());
832 <        assertEquals(1, lock.getReadLockCount());
833 <        lock.unlockRead(p);
834 <
835 <        assertTrue((s = lock.readLock()) != 0L);
836 <        assertTrue(lock.validate(s));
837 <        assertEquals(s, lock.tryConvertToReadLock(s));
838 <        assertTrue(lock.validate(s));
839 <        assertTrue(lock.isReadLocked());
840 <        assertEquals(1, lock.getReadLockCount());
841 <        lock.unlockRead(s);
842 <
843 <        assertTrue((s = lock.tryWriteLock()) != 0L);
844 <        assertTrue(lock.validate(s));
845 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
846 <        assertTrue(lock.validate(p));
812 <        assertEquals(1, lock.getReadLockCount());
813 <        lock.unlockRead(p);
814 <
815 <        assertTrue((s = lock.tryReadLock()) != 0L);
816 <        assertTrue(lock.validate(s));
817 <        assertEquals(s, lock.tryConvertToReadLock(s));
818 <        assertTrue(lock.validate(s));
819 <        assertTrue(lock.isReadLocked());
820 <        assertEquals(1, lock.getReadLockCount());
821 <        lock.unlockRead(s);
822 <
823 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
824 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
825 <        assertTrue(lock.validate(p));
826 <        assertTrue(lock.isReadLocked());
827 <        assertEquals(1, lock.getReadLockCount());
828 <        lock.unlockRead(p);
829 <
830 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
831 <        assertTrue(lock.validate(s));
832 <        assertEquals(s, lock.tryConvertToReadLock(s));
833 <        assertTrue(lock.validate(s));
834 <        assertTrue(lock.isReadLocked());
835 <        assertEquals(1, lock.getReadLockCount());
836 <        lock.unlockRead(s);
828 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
829 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
830 >                s = assertValid(lock, writeLocker.apply(lock));
831 >                p = assertValid(lock, lock.tryConvertToReadLock(s));
832 >                assertFalse(lock.validate(s));
833 >                assertTrue(lock.isReadLocked());
834 >                assertEquals(1, lock.getReadLockCount());
835 >                readUnlocker.accept(lock, p);
836 >            }
837 >
838 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
839 >                s = assertValid(lock, readLocker.apply(lock));
840 >                assertEquals(s, lock.tryConvertToReadLock(s));
841 >                assertTrue(lock.validate(s));
842 >                assertTrue(lock.isReadLocked());
843 >                assertEquals(1, lock.getReadLockCount());
844 >                readUnlocker.accept(lock, s);
845 >            }
846 >        }
847      }
848  
849      /**
850 <     * tryConvertToWriteLock succeeds and validates if successfully locked
841 <     * or lock free;
850 >     * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
851       */
852      public void testTryConvertToWriteLock() throws InterruptedException {
853          StampedLock lock = new StampedLock();
854          long s, p;
855  
856 <        assertFalse((p = lock.tryConvertToWriteLock(0L)) != 0L);
856 >        assertEquals(0L, lock.tryConvertToWriteLock(0L));
857  
858          assertTrue((s = lock.tryOptimisticRead()) != 0L);
859          assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
860          assertTrue(lock.isWriteLocked());
861          lock.unlockWrite(p);
862  
863 <        assertTrue((s = lock.writeLock()) != 0L);
864 <        assertEquals(s, lock.tryConvertToWriteLock(s));
865 <        assertTrue(lock.validate(s));
866 <        assertTrue(lock.isWriteLocked());
867 <        lock.unlockWrite(s);
868 <
869 <        assertTrue((s = lock.readLock()) != 0L);
870 <        assertTrue(lock.validate(s));
871 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
872 <        assertTrue(lock.validate(p));
873 <        assertTrue(lock.isWriteLocked());
874 <        lock.unlockWrite(p);
875 <
876 <        assertTrue((s = lock.tryWriteLock()) != 0L);
877 <        assertTrue(lock.validate(s));
878 <        assertEquals(s, lock.tryConvertToWriteLock(s));
879 <        assertTrue(lock.validate(s));
880 <        assertTrue(lock.isWriteLocked());
872 <        lock.unlockWrite(s);
873 <
874 <        assertTrue((s = lock.tryReadLock()) != 0L);
875 <        assertTrue(lock.validate(s));
876 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
877 <        assertTrue(lock.validate(p));
878 <        assertTrue(lock.isWriteLocked());
879 <        lock.unlockWrite(p);
880 <
881 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
882 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
883 <        assertTrue(lock.validate(p));
884 <        assertTrue(lock.isWriteLocked());
885 <        lock.unlockWrite(p);
863 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
864 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
865 >                s = assertValid(lock, writeLocker.apply(lock));
866 >                assertEquals(s, lock.tryConvertToWriteLock(s));
867 >                assertTrue(lock.validate(s));
868 >                assertTrue(lock.isWriteLocked());
869 >                writeUnlocker.accept(lock, s);
870 >            }
871 >
872 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
873 >                s = assertValid(lock, readLocker.apply(lock));
874 >                p = assertValid(lock, lock.tryConvertToWriteLock(s));
875 >                assertFalse(lock.validate(s));
876 >                assertTrue(lock.validate(p));
877 >                assertTrue(lock.isWriteLocked());
878 >                writeUnlocker.accept(lock, p);
879 >            }
880 >        }
881  
882 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
883 <        assertTrue(lock.validate(s));
884 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
885 <        assertTrue(lock.validate(p));
886 <        assertTrue(lock.isWriteLocked());
887 <        lock.unlockWrite(p);
882 >        // failure if multiply read locked
883 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
884 >            s = assertValid(lock, readLocker.apply(lock));
885 >            p = assertValid(lock, readLocker.apply(lock));
886 >            assertEquals(0L, lock.tryConvertToWriteLock(s));
887 >            assertTrue(lock.validate(s));
888 >            assertTrue(lock.validate(p));
889 >            assertEquals(2, lock.getReadLockCount());
890 >            lock.unlock(p);
891 >            lock.unlock(s);
892 >            assertUnlocked(lock);
893 >        }
894      }
895  
896      /**
897       * asWriteLock can be locked and unlocked
898       */
899 <    public void testAsWriteLock() {
899 >    public void testAsWriteLock() throws Throwable {
900          StampedLock sl = new StampedLock();
901          Lock lock = sl.asWriteLock();
902 <        lock.lock();
903 <        assertFalse(lock.tryLock());
904 <        lock.unlock();
905 <        assertTrue(lock.tryLock());
902 >        for (Action locker : lockLockers(lock)) {
903 >            locker.run();
904 >            assertTrue(sl.isWriteLocked());
905 >            assertFalse(sl.isReadLocked());
906 >            assertFalse(lock.tryLock());
907 >            lock.unlock();
908 >            assertUnlocked(sl);
909 >        }
910      }
911  
912      /**
913       * asReadLock can be locked and unlocked
914       */
915 <    public void testAsReadLock() {
915 >    public void testAsReadLock() throws Throwable {
916          StampedLock sl = new StampedLock();
917          Lock lock = sl.asReadLock();
918 <        lock.lock();
919 <        lock.unlock();
920 <        assertTrue(lock.tryLock());
918 >        for (Action locker : lockLockers(lock)) {
919 >            locker.run();
920 >            assertTrue(sl.isReadLocked());
921 >            assertFalse(sl.isWriteLocked());
922 >            assertEquals(1, sl.getReadLockCount());
923 >            locker.run();
924 >            assertTrue(sl.isReadLocked());
925 >            assertEquals(2, sl.getReadLockCount());
926 >            lock.unlock();
927 >            lock.unlock();
928 >            assertUnlocked(sl);
929 >        }
930      }
931  
932      /**
933       * asReadWriteLock.writeLock can be locked and unlocked
934       */
935 <    public void testAsReadWriteLockWriteLock() {
935 >    public void testAsReadWriteLockWriteLock() throws Throwable {
936          StampedLock sl = new StampedLock();
937          Lock lock = sl.asReadWriteLock().writeLock();
938 <        lock.lock();
939 <        assertFalse(lock.tryLock());
940 <        lock.unlock();
941 <        assertTrue(lock.tryLock());
938 >        for (Action locker : lockLockers(lock)) {
939 >            locker.run();
940 >            assertTrue(sl.isWriteLocked());
941 >            assertFalse(sl.isReadLocked());
942 >            assertFalse(lock.tryLock());
943 >            lock.unlock();
944 >            assertUnlocked(sl);
945 >        }
946      }
947  
948      /**
949       * asReadWriteLock.readLock can be locked and unlocked
950       */
951 <    public void testAsReadWriteLockReadLock() {
951 >    public void testAsReadWriteLockReadLock() throws Throwable {
952          StampedLock sl = new StampedLock();
953          Lock lock = sl.asReadWriteLock().readLock();
954 <        lock.lock();
955 <        lock.unlock();
956 <        assertTrue(lock.tryLock());
954 >        for (Action locker : lockLockers(lock)) {
955 >            locker.run();
956 >            assertTrue(sl.isReadLocked());
957 >            assertFalse(sl.isWriteLocked());
958 >            assertEquals(1, sl.getReadLockCount());
959 >            locker.run();
960 >            assertTrue(sl.isReadLocked());
961 >            assertEquals(2, sl.getReadLockCount());
962 >            lock.unlock();
963 >            lock.unlock();
964 >            assertUnlocked(sl);
965 >        }
966      }
967  
968      /**
# Line 958 | Line 985 | public class StampedLockTest extends JSR
985          Runnable[] actions = {
986              () -> {
987                  StampedLock sl = new StampedLock();
988 <                long stamp = sl.tryOptimisticRead();
962 <                assertTrue(stamp != 0);
988 >                long stamp = assertValid(sl, sl.tryOptimisticRead());
989                  sl.unlockRead(stamp);
990              },
991              () -> {
# Line 976 | Line 1002 | public class StampedLockTest extends JSR
1002              },
1003              () -> {
1004                  StampedLock sl = new StampedLock();
979                long stamp = sl.tryOptimisticRead();
1005                  sl.readLock();
1006 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
1007                  sl.unlockRead(stamp);
1008              },
1009              () -> {
1010                  StampedLock sl = new StampedLock();
985                long stamp = sl.tryOptimisticRead();
1011                  sl.readLock();
1012 +                long stamp = assertValid(sl, sl.tryOptimisticRead());
1013                  sl.unlock(stamp);
1014              },
1015  
1016              () -> {
1017                  StampedLock sl = new StampedLock();
1018                  long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1019 <                assertTrue(stamp != 0);
1019 >                assertValid(sl, stamp);
1020                  sl.writeLock();
1021                  sl.unlockWrite(stamp);
1022              },
# Line 1016 | Line 1042 | public class StampedLockTest extends JSR
1042              () -> {
1043                  StampedLock sl = new StampedLock();
1044                  long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1045 <                assertTrue(stamp != 0);
1045 >                assertValid(sl, stamp);
1046                  sl.writeLock();
1047                  sl.unlockWrite(stamp);
1048              },
# Line 1036 | Line 1062 | public class StampedLockTest extends JSR
1062                  StampedLock sl = new StampedLock();
1063                  sl.readLock();
1064                  long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1065 <                assertTrue(stamp != 0);
1065 >                assertValid(sl, stamp);
1066                  sl.readLock();
1067                  sl.unlockRead(stamp);
1068              },
# Line 1079 | Line 1105 | public class StampedLockTest extends JSR
1105      }
1106  
1107      /**
1108 <     * Invalid write stamps result in IllegalMonitorStateException
1108 >     * Invalid stamps result in IllegalMonitorStateException
1109       */
1110 <    public void testInvalidWriteStampsThrowIllegalMonitorStateException() {
1111 <        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
1086 <        writeLockers.add((sl) -> sl.writeLock());
1087 <        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
1088 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1089 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
1110 >    public void testInvalidStampsThrowIllegalMonitorStateException() {
1111 >        final StampedLock sl = new StampedLock();
1112  
1113 <        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
1114 <        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
1115 <        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
1116 <        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
1117 <        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1113 >        assertThrows(IllegalMonitorStateException.class,
1114 >                     () -> sl.unlockWrite(0L),
1115 >                     () -> sl.unlockRead(0L),
1116 >                     () -> sl.unlock(0L));
1117 >
1118 >        final long optimisticStamp = sl.tryOptimisticRead();
1119 >        final long readStamp = sl.readLock();
1120 >        sl.unlockRead(readStamp);
1121 >        final long writeStamp = sl.writeLock();
1122 >        sl.unlockWrite(writeStamp);
1123 >        assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1124 >        final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1125 >        final Runnable assertNoLongerValidStampsThrow = () -> {
1126 >            for (long noLongerValidStamp : noLongerValidStamps)
1127 >                assertThrows(IllegalMonitorStateException.class,
1128 >                             () -> sl.unlockWrite(noLongerValidStamp),
1129 >                             () -> sl.unlockRead(noLongerValidStamp),
1130 >                             () -> sl.unlock(noLongerValidStamp));
1131 >        };
1132 >        assertNoLongerValidStampsThrow.run();
1133  
1134 <        List<Consumer<StampedLock>> mutaters = new ArrayList<>();
1135 <        mutaters.add((sl) -> {});
1136 <        mutaters.add((sl) -> sl.readLock());
1137 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1138 <            mutaters.add((sl) -> writeLocker.apply(sl));
1102 <
1103 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1104 <        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers)
1105 <        for (Consumer<StampedLock> mutater : mutaters) {
1106 <            final StampedLock sl = new StampedLock();
1107 <            final long stamp = writeLocker.apply(sl);
1108 <            assertTrue(stamp != 0L);
1134 >        for (Function<StampedLock, Long> readLocker : readLockers())
1135 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1136 >            final long stamp = readLocker.apply(sl);
1137 >            assertValid(sl, stamp);
1138 >            assertNoLongerValidStampsThrow.run();
1139              assertThrows(IllegalMonitorStateException.class,
1140 <                         () -> sl.unlockRead(stamp));
1141 <            writeUnlocker.accept(sl, stamp);
1142 <            mutater.accept(sl);
1140 >                         () -> sl.unlockWrite(stamp),
1141 >                         () -> sl.unlockRead(sl.tryOptimisticRead()),
1142 >                         () -> sl.unlockRead(0L));
1143 >            readUnlocker.accept(sl, stamp);
1144 >            assertUnlocked(sl);
1145 >            assertNoLongerValidStampsThrow.run();
1146 >        }
1147 >
1148 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
1149 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1150 >            final long stamp = writeLocker.apply(sl);
1151 >            assertValid(sl, stamp);
1152 >            assertNoLongerValidStampsThrow.run();
1153              assertThrows(IllegalMonitorStateException.class,
1114                         () -> sl.unlock(stamp),
1154                           () -> sl.unlockRead(stamp),
1155 <                         () -> sl.unlockWrite(stamp));
1155 >                         () -> sl.unlockWrite(0L));
1156 >            writeUnlocker.accept(sl, stamp);
1157 >            assertUnlocked(sl);
1158 >            assertNoLongerValidStampsThrow.run();
1159          }
1160      }
1161  
1162      /**
1163 <     * Invalid read stamps result in IllegalMonitorStateException
1163 >     * Read locks can be very deeply nested
1164       */
1165 <    public void testInvalidReadStampsThrowIllegalMonitorStateException() {
1166 <        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
1167 <        readLockers.add((sl) -> sl.readLock());
1168 <        readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
1169 <        readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1170 <        readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0, DAYS));
1165 >    public void testDeeplyNestedReadLocks() {
1166 >        final StampedLock lock = new StampedLock();
1167 >        final int depth = 300;
1168 >        final long[] stamps = new long[depth];
1169 >        final List<Function<StampedLock, Long>> readLockers = readLockers();
1170 >        final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1171 >        for (int i = 0; i < depth; i++) {
1172 >            Function<StampedLock, Long> readLocker
1173 >                = readLockers.get(i % readLockers.size());
1174 >            long stamp = readLocker.apply(lock);
1175 >            assertEquals(i + 1, lock.getReadLockCount());
1176 >            assertTrue(lock.isReadLocked());
1177 >            stamps[i] = stamp;
1178 >        }
1179 >        for (int i = 0; i < depth; i++) {
1180 >            BiConsumer<StampedLock, Long> readUnlocker
1181 >                = readUnlockers.get(i % readUnlockers.size());
1182 >            assertEquals(depth - i, lock.getReadLockCount());
1183 >            assertTrue(lock.isReadLocked());
1184 >            readUnlocker.accept(lock, stamps[depth - 1 - i]);
1185 >        }
1186 >        assertUnlocked(lock);
1187 >    }
1188  
1189 <        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
1190 <        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
1191 <        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
1192 <        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
1193 <        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1189 >    /**
1190 >     * Stamped locks are not reentrant.
1191 >     */
1192 >    public void testNonReentrant() throws InterruptedException {
1193 >        final StampedLock lock = new StampedLock();
1194 >        long stamp;
1195  
1196 <        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
1197 <        writeLockers.add((sl) -> sl.writeLock());
1198 <        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
1199 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1200 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
1196 >        stamp = lock.writeLock();
1197 >        assertValid(lock, stamp);
1198 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1199 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
1200 >        assertValid(lock, stamp);
1201 >        lock.unlockWrite(stamp);
1202 >
1203 >        stamp = lock.tryWriteLock(1L, DAYS);
1204 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1205 >        assertValid(lock, stamp);
1206 >        lock.unlockWrite(stamp);
1207 >
1208 >        stamp = lock.readLock();
1209 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1210 >        assertValid(lock, stamp);
1211 >        lock.unlockRead(stamp);
1212 >    }
1213  
1214 <        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
1215 <        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
1216 <        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
1217 <        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
1218 <        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1214 >    /**
1215 >     * """StampedLocks have no notion of ownership. Locks acquired in
1216 >     * one thread can be released or converted in another."""
1217 >     */
1218 >    public void testNoOwnership() throws Throwable {
1219 >        ArrayList<Future<?>> futures = new ArrayList<>();
1220 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
1221 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1222 >            StampedLock lock = new StampedLock();
1223 >            long stamp = writeLocker.apply(lock);
1224 >            futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1225 >                public void realRun() {
1226 >                    writeUnlocker.accept(lock, stamp);
1227 >                    assertUnlocked(lock);
1228 >                    assertFalse(lock.validate(stamp));
1229 >                }}));
1230 >        }
1231 >        for (Future<?> future : futures)
1232 >            assertNull(future.get());
1233 >    }
1234  
1235 +    /** Tries out sample usage code from StampedLock javadoc. */
1236 +    public void testSampleUsage() throws Throwable {
1237 +        class Point {
1238 +            private double x, y;
1239 +            private final StampedLock sl = new StampedLock();
1240 +
1241 +            void move(double deltaX, double deltaY) { // an exclusively locked method
1242 +                long stamp = sl.writeLock();
1243 +                try {
1244 +                    x += deltaX;
1245 +                    y += deltaY;
1246 +                } finally {
1247 +                    sl.unlockWrite(stamp);
1248 +                }
1249 +            }
1250  
1251 <        for (Function<StampedLock, Long> readLocker : readLockers)
1252 <        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers)
1253 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1254 <        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers) {
1255 <            final StampedLock sl = new StampedLock();
1256 <            final long stamp = readLocker.apply(sl);
1257 <            assertTrue(stamp != 0L);
1258 <            assertThrows(IllegalMonitorStateException.class,
1259 <                         () -> sl.unlockWrite(stamp));
1260 <            readUnlocker.accept(sl, stamp);
1261 <            assertThrows(IllegalMonitorStateException.class,
1262 <                         () -> sl.unlock(stamp),
1263 <                         () -> sl.unlockRead(stamp),
1264 <                         () -> sl.unlockWrite(stamp));
1265 <            final long writeStamp = writeLocker.apply(sl);
1266 <            assertTrue(writeStamp != 0L);
1267 <            assertTrue(writeStamp != stamp);
1268 <            assertThrows(IllegalMonitorStateException.class,
1269 <                         () -> sl.unlock(stamp),
1270 <                         () -> sl.unlockRead(stamp),
1271 <                         () -> sl.unlockWrite(stamp));
1272 <            writeUnlocker.accept(sl, writeStamp);
1273 <            assertThrows(IllegalMonitorStateException.class,
1274 <                         () -> sl.unlock(stamp),
1275 <                         () -> sl.unlockRead(stamp),
1276 <                         () -> sl.unlockWrite(stamp));
1251 >            double distanceFromOrigin() { // A read-only method
1252 >                double currentX, currentY;
1253 >                long stamp = sl.tryOptimisticRead();
1254 >                do {
1255 >                    if (stamp == 0L)
1256 >                        stamp = sl.readLock();
1257 >                    try {
1258 >                        // possibly racy reads
1259 >                        currentX = x;
1260 >                        currentY = y;
1261 >                    } finally {
1262 >                        stamp = sl.tryConvertToOptimisticRead(stamp);
1263 >                    }
1264 >                } while (stamp == 0);
1265 >                return Math.hypot(currentX, currentY);
1266 >            }
1267 >
1268 >            double distanceFromOrigin2() {
1269 >                long stamp = sl.tryOptimisticRead();
1270 >                try {
1271 >                    retryHoldingLock:
1272 >                    for (;; stamp = sl.readLock()) {
1273 >                        if (stamp == 0L)
1274 >                            continue retryHoldingLock;
1275 >                        // possibly racy reads
1276 >                        double currentX = x;
1277 >                        double currentY = y;
1278 >                        if (!sl.validate(stamp))
1279 >                            continue retryHoldingLock;
1280 >                        return Math.hypot(currentX, currentY);
1281 >                    }
1282 >                } finally {
1283 >                    if (StampedLock.isReadLockStamp(stamp))
1284 >                        sl.unlockRead(stamp);
1285 >                }
1286 >            }
1287 >
1288 >            void moveIfAtOrigin(double newX, double newY) {
1289 >                long stamp = sl.readLock();
1290 >                try {
1291 >                    while (x == 0.0 && y == 0.0) {
1292 >                        long ws = sl.tryConvertToWriteLock(stamp);
1293 >                        if (ws != 0L) {
1294 >                            stamp = ws;
1295 >                            x = newX;
1296 >                            y = newY;
1297 >                            return;
1298 >                        }
1299 >                        else {
1300 >                            sl.unlockRead(stamp);
1301 >                            stamp = sl.writeLock();
1302 >                        }
1303 >                    }
1304 >                } finally {
1305 >                    sl.unlock(stamp);
1306 >                }
1307 >            }
1308 >        }
1309 >
1310 >        Point p = new Point();
1311 >        p.move(3.0, 4.0);
1312 >        assertEquals(5.0, p.distanceFromOrigin());
1313 >        p.moveIfAtOrigin(5.0, 12.0);
1314 >        assertEquals(5.0, p.distanceFromOrigin2());
1315 >    }
1316 >
1317 >    /**
1318 >     * Stamp inspection methods work as expected, and do not inspect
1319 >     * the state of the lock itself.
1320 >     */
1321 >    public void testStampStateInspectionMethods() {
1322 >        StampedLock lock = new StampedLock();
1323 >
1324 >        assertFalse(isWriteLockStamp(0L));
1325 >        assertFalse(isReadLockStamp(0L));
1326 >        assertFalse(isLockStamp(0L));
1327 >        assertFalse(isOptimisticReadStamp(0L));
1328 >
1329 >        {
1330 >            long stamp = lock.writeLock();
1331 >            for (int i = 0; i < 2; i++) {
1332 >                assertTrue(isWriteLockStamp(stamp));
1333 >                assertFalse(isReadLockStamp(stamp));
1334 >                assertTrue(isLockStamp(stamp));
1335 >                assertFalse(isOptimisticReadStamp(stamp));
1336 >                if (i == 0)
1337 >                    lock.unlockWrite(stamp);
1338 >            }
1339 >        }
1340 >
1341 >        {
1342 >            long stamp = lock.readLock();
1343 >            for (int i = 0; i < 2; i++) {
1344 >                assertFalse(isWriteLockStamp(stamp));
1345 >                assertTrue(isReadLockStamp(stamp));
1346 >                assertTrue(isLockStamp(stamp));
1347 >                assertFalse(isOptimisticReadStamp(stamp));
1348 >                if (i == 0)
1349 >                    lock.unlockRead(stamp);
1350 >            }
1351 >        }
1352 >
1353 >        {
1354 >            long optimisticStamp = lock.tryOptimisticRead();
1355 >            long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1356 >            long writeStamp = lock.tryConvertToWriteLock(readStamp);
1357 >            for (int i = 0; i < 2; i++) {
1358 >                assertFalse(isWriteLockStamp(optimisticStamp));
1359 >                assertFalse(isReadLockStamp(optimisticStamp));
1360 >                assertFalse(isLockStamp(optimisticStamp));
1361 >                assertTrue(isOptimisticReadStamp(optimisticStamp));
1362 >
1363 >                assertFalse(isWriteLockStamp(readStamp));
1364 >                assertTrue(isReadLockStamp(readStamp));
1365 >                assertTrue(isLockStamp(readStamp));
1366 >                assertFalse(isOptimisticReadStamp(readStamp));
1367 >
1368 >                assertTrue(isWriteLockStamp(writeStamp));
1369 >                assertFalse(isReadLockStamp(writeStamp));
1370 >                assertTrue(isLockStamp(writeStamp));
1371 >                assertFalse(isOptimisticReadStamp(writeStamp));
1372 >                if (i == 0)
1373 >                    lock.unlockWrite(writeStamp);
1374 >            }
1375          }
1376      }
1377  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines