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.45 by jsr166, Wed Aug 12 16:12:23 2020 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.Callable;
19 + import java.util.concurrent.CompletableFuture;
20   import java.util.concurrent.CountDownLatch;
21 + import java.util.concurrent.Future;
22 + import java.util.concurrent.ThreadLocalRandom;
23   import java.util.concurrent.TimeUnit;
24 + import java.util.concurrent.atomic.AtomicBoolean;
25   import java.util.concurrent.locks.Lock;
26   import java.util.concurrent.locks.StampedLock;
27   import java.util.function.BiConsumer;
# Line 30 | Line 40 | public class StampedLockTest extends JSR
40      }
41  
42      /**
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    /**
43       * Releases write lock, checking isWriteLocked before and after
44       */
45 <    void releaseWriteLock(StampedLock lock, long s) {
45 >    void releaseWriteLock(StampedLock lock, long stamp) {
46          assertTrue(lock.isWriteLocked());
47 <        lock.unlockWrite(s);
47 >        assertValid(lock, stamp);
48 >        lock.unlockWrite(stamp);
49          assertFalse(lock.isWriteLocked());
50 +        assertFalse(lock.validate(stamp));
51      }
52  
53      /**
54 <     * Constructed StampedLock is in unlocked state
54 >     * Releases read lock, checking isReadLocked before and after
55       */
56 <    public void testConstructor() {
57 <        StampedLock lock;
58 <        lock = new StampedLock();
59 <        assertFalse(lock.isWriteLocked());
56 >    void releaseReadLock(StampedLock lock, long stamp) {
57 >        assertTrue(lock.isReadLocked());
58 >        assertValid(lock, stamp);
59 >        lock.unlockRead(stamp);
60          assertFalse(lock.isReadLocked());
61 <        assertEquals(lock.getReadLockCount(), 0);
61 >        assertTrue(lock.validate(stamp));
62      }
63  
64 <    /**
65 <     * write-locking and read-locking an unlocked lock succeed
66 <     */
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);
64 >    long assertNonZero(long v) {
65 >        assertTrue(v != 0L);
66 >        return v;
67      }
68  
69 <    /**
70 <     * unlock releases either a read or write lock
71 <     */
72 <    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);
69 >    long assertValid(StampedLock lock, long stamp) {
70 >        assertTrue(stamp != 0L);
71 >        assertTrue(lock.validate(stamp));
72 >        return stamp;
73      }
74  
75 <    /**
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());
134 <        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());
75 >    void assertUnlocked(StampedLock lock) {
76          assertFalse(lock.isReadLocked());
146        assertEquals(lock.getReadLockCount(), 0);
147        long rs = lock.readLock();
77          assertFalse(lock.isWriteLocked());
78 <        assertTrue(lock.isReadLocked());
79 <        assertEquals(lock.getReadLockCount(), 1);
151 <        assertFalse(lock.tryUnlockWrite());
152 <        assertTrue(lock.tryUnlockRead());
153 <        assertFalse(lock.tryUnlockRead());
154 <        assertFalse(lock.tryUnlockWrite());
155 <        assertFalse(lock.isWriteLocked());
156 <        assertFalse(lock.isReadLocked());
157 <        assertEquals(lock.getReadLockCount(), 0);
78 >        assertEquals(0, lock.getReadLockCount());
79 >        assertValid(lock, lock.tryOptimisticRead());
80      }
81  
82 <    /**
83 <     * write-unlocking an unlocked lock throws IllegalMonitorStateException
84 <     */
85 <    public void testWriteUnlock_IMSE() {
86 <        StampedLock lock = new StampedLock();
87 <        try {
88 <            lock.unlockWrite(0L);
89 <            shouldThrow();
90 <        } catch (IllegalMonitorStateException success) {}
82 >    List<Action> lockLockers(Lock lock) {
83 >        return List.of(
84 >            () -> lock.lock(),
85 >            () -> lock.lockInterruptibly(),
86 >            () -> lock.tryLock(),
87 >            () -> lock.tryLock(Long.MIN_VALUE, DAYS),
88 >            () -> lock.tryLock(0L, DAYS),
89 >            () -> lock.tryLock(Long.MAX_VALUE, DAYS));
90 >    }
91 >
92 >    List<Function<StampedLock, Long>> readLockers() {
93 >        return List.of(
94 >            sl -> sl.readLock(),
95 >            sl -> sl.tryReadLock(),
96 >            sl -> readLockInterruptiblyUninterrupted(sl),
97 >            sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS),
98 >            sl -> tryReadLockUninterrupted(sl, 0L, DAYS),
99 >            sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
100 >    }
101 >
102 >    List<BiConsumer<StampedLock, Long>> readUnlockers() {
103 >        return List.of(
104 >            (sl, stamp) -> sl.unlockRead(stamp),
105 >            (sl, stamp) -> assertTrue(sl.tryUnlockRead()),
106 >            (sl, stamp) -> sl.asReadLock().unlock(),
107 >            (sl, stamp) -> sl.unlock(stamp),
108 >            (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
109 >    }
110 >
111 >    List<Function<StampedLock, Long>> writeLockers() {
112 >        return List.of(
113 >            sl -> sl.writeLock(),
114 >            sl -> sl.tryWriteLock(),
115 >            sl -> writeLockInterruptiblyUninterrupted(sl),
116 >            sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS),
117 >            sl -> tryWriteLockUninterrupted(sl, 0L, DAYS),
118 >            sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
119 >    }
120 >
121 >    List<BiConsumer<StampedLock, Long>> writeUnlockers() {
122 >        return List.of(
123 >            (sl, stamp) -> sl.unlockWrite(stamp),
124 >            (sl, stamp) -> assertTrue(sl.tryUnlockWrite()),
125 >            (sl, stamp) -> sl.asWriteLock().unlock(),
126 >            (sl, stamp) -> sl.unlock(stamp),
127 >            (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
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 <            }});
346 >        long stamp = lock.writeLock();
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 >        releaseWriteLock(lock, stamp);
363      }
364  
365      /**
366 <     * readLockInterruptibly is interruptible
366 >     * interruptible operations throw InterruptedException when read locked and interrupted
367       */
368 <    public void testReadLockInterruptibly_Interruptible()
327 <            throws InterruptedException {
328 <        final CountDownLatch running = new CountDownLatch(1);
368 >    public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
369          final StampedLock lock = new StampedLock();
370 <        long s = lock.writeLock();
331 <        Thread t = newStartedThread(new CheckedInterruptedRunnable() {
332 <            public void realRun() throws InterruptedException {
333 <                running.countDown();
334 <                lock.readLockInterruptibly();
335 <            }});
370 >        long stamp = lock.readLock();
371  
372 <        running.await();
373 <        waitForThreadToEnterWaitState(t, 100);
374 <        t.interrupt();
375 <        awaitTermination(t);
376 <        releaseWriteLock(lock, s);
372 >        Action[] interruptibleLockBlockingActions = {
373 >            () -> lock.writeLockInterruptibly(),
374 >            () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
375 >            () -> lock.asWriteLock().lockInterruptibly(),
376 >            () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
377 >        };
378 >        shuffle(interruptibleLockBlockingActions);
379 >
380 >        assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
381 >
382 >        releaseReadLock(lock, stamp);
383      }
384  
385      /**
386 <     * timed tryReadLock is interruptible
386 >     * Non-interruptible operations ignore and preserve interrupt status
387       */
388 <    public void testReadTryLock_Interruptible() throws InterruptedException {
348 <        final CountDownLatch running = new CountDownLatch(1);
388 >    public void testNonInterruptibleOperationsIgnoreInterrupts() {
389          final StampedLock lock = new StampedLock();
390 <        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 <            }});
390 >        Thread.currentThread().interrupt();
391  
392 <        running.await();
393 <        waitForThreadToEnterWaitState(t, 100);
394 <        t.interrupt();
395 <        awaitTermination(t);
396 <        releaseWriteLock(lock, s);
392 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
393 >            long s = assertValid(lock, lock.readLock());
394 >            readUnlocker.accept(lock, s);
395 >            s = assertValid(lock, lock.tryReadLock());
396 >            readUnlocker.accept(lock, s);
397 >        }
398 >
399 >        lock.asReadLock().lock();
400 >        lock.asReadLock().unlock();
401 >
402 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
403 >            long s = assertValid(lock, lock.writeLock());
404 >            writeUnlocker.accept(lock, s);
405 >            s = assertValid(lock, lock.tryWriteLock());
406 >            writeUnlocker.accept(lock, s);
407 >        }
408 >
409 >        lock.asWriteLock().lock();
410 >        lock.asWriteLock().unlock();
411 >
412 >        assertTrue(Thread.interrupted());
413      }
414  
415      /**
416       * tryWriteLock on an unlocked lock succeeds
417       */
418 <    public void testWriteTryLock() {
418 >    public void testTryWriteLock() {
419          final StampedLock lock = new StampedLock();
420          long s = lock.tryWriteLock();
421          assertTrue(s != 0L);
422          assertTrue(lock.isWriteLocked());
423 <        long s2 = lock.tryWriteLock();
373 <        assertEquals(s2, 0L);
423 >        assertEquals(0L, lock.tryWriteLock());
424          releaseWriteLock(lock, s);
425      }
426  
427      /**
428       * tryWriteLock fails if locked
429       */
430 <    public void testWriteTryLockWhenLocked() {
430 >    public void testTryWriteLockWhenLocked() {
431          final StampedLock lock = new StampedLock();
432          long s = lock.writeLock();
433          Thread t = newStartedThread(new CheckedRunnable() {
434              public void realRun() {
435 <                long ws = lock.tryWriteLock();
386 <                assertTrue(ws == 0L);
435 >                assertEquals(0L, lock.tryWriteLock());
436              }});
437  
438 +        assertEquals(0L, lock.tryWriteLock());
439          awaitTermination(t);
440          releaseWriteLock(lock, s);
441      }
# Line 393 | Line 443 | public class StampedLockTest extends JSR
443      /**
444       * tryReadLock fails if write-locked
445       */
446 <    public void testReadTryLockWhenLocked() {
446 >    public void testTryReadLockWhenLocked() {
447          final StampedLock lock = new StampedLock();
448          long s = lock.writeLock();
449          Thread t = newStartedThread(new CheckedRunnable() {
450              public void realRun() {
451 <                long rs = lock.tryReadLock();
402 <                assertEquals(rs, 0L);
451 >                assertEquals(0L, lock.tryReadLock());
452              }});
453  
454 +        assertEquals(0L, lock.tryReadLock());
455          awaitTermination(t);
456          releaseWriteLock(lock, s);
457      }
# Line 415 | Line 465 | public class StampedLockTest extends JSR
465          Thread t = newStartedThread(new CheckedRunnable() {
466              public void realRun() throws InterruptedException {
467                  long s2 = lock.tryReadLock();
468 <                assertTrue(s2 != 0L);
468 >                assertValid(lock, s2);
469                  lock.unlockRead(s2);
470                  long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
471 <                assertTrue(s3 != 0L);
471 >                assertValid(lock, s3);
472                  lock.unlockRead(s3);
473                  long s4 = lock.readLock();
474 +                assertValid(lock, s4);
475                  lock.unlockRead(s4);
476 +                lock.asReadLock().lock();
477 +                lock.asReadLock().unlock();
478 +                lock.asReadLock().lockInterruptibly();
479 +                lock.asReadLock().unlock();
480 +                lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
481 +                lock.asReadLock().unlock();
482              }});
483  
484          awaitTermination(t);
# Line 429 | Line 486 | public class StampedLockTest extends JSR
486      }
487  
488      /**
489 <     * A writelock succeeds only after a reading thread unlocks
489 >     * writeLock() succeeds only after a reading thread unlocks
490       */
491      public void testWriteAfterReadLock() throws InterruptedException {
492 <        final CountDownLatch running = new CountDownLatch(1);
492 >        final CountDownLatch aboutToLock = new CountDownLatch(1);
493          final StampedLock lock = new StampedLock();
494          long rs = lock.readLock();
495          Thread t = newStartedThread(new CheckedRunnable() {
496              public void realRun() {
497 <                running.countDown();
497 >                aboutToLock.countDown();
498                  long s = lock.writeLock();
499 +                assertTrue(lock.isWriteLocked());
500 +                assertFalse(lock.isReadLocked());
501                  lock.unlockWrite(s);
502              }});
503  
504 <        running.await();
505 <        waitForThreadToEnterWaitState(t, 100);
504 >        await(aboutToLock);
505 >        assertThreadBlocks(t, Thread.State.WAITING);
506          assertFalse(lock.isWriteLocked());
507 +        assertTrue(lock.isReadLocked());
508          lock.unlockRead(rs);
509          awaitTermination(t);
510 <        assertFalse(lock.isWriteLocked());
510 >        assertUnlocked(lock);
511      }
512  
513      /**
514 <     * A writelock succeeds only after reading threads unlock
514 >     * writeLock() succeeds only after reading threads unlock
515       */
516      public void testWriteAfterMultipleReadLocks() {
517          final StampedLock lock = new StampedLock();
# Line 470 | Line 530 | public class StampedLockTest extends JSR
530                  lock.unlockWrite(ws);
531              }});
532  
533 +        assertTrue(lock.isReadLocked());
534          assertFalse(lock.isWriteLocked());
535          lock.unlockRead(s);
536          awaitTermination(t2);
537 <        assertFalse(lock.isWriteLocked());
537 >        assertUnlocked(lock);
538      }
539  
540      /**
541 <     * Readlocks succeed only after a writing thread unlocks
541 >     * readLock() succeed only after a writing thread unlocks
542       */
543      public void testReadAfterWriteLock() {
544          final StampedLock lock = new StampedLock();
545 +        final CountDownLatch threadsStarted = new CountDownLatch(2);
546          final long s = lock.writeLock();
547 <        Thread t1 = newStartedThread(new CheckedRunnable() {
486 <            public void realRun() {
487 <                long rs = lock.readLock();
488 <                lock.unlockRead(rs);
489 <            }});
490 <        Thread t2 = newStartedThread(new CheckedRunnable() {
547 >        final Runnable acquireReleaseReadLock = new CheckedRunnable() {
548              public void realRun() {
549 +                threadsStarted.countDown();
550                  long rs = lock.readLock();
551 +                assertTrue(lock.isReadLocked());
552 +                assertFalse(lock.isWriteLocked());
553                  lock.unlockRead(rs);
554 <            }});
555 <
554 >            }};
555 >        Thread t1 = newStartedThread(acquireReleaseReadLock);
556 >        Thread t2 = newStartedThread(acquireReleaseReadLock);
557 >
558 >        await(threadsStarted);
559 >        assertThreadBlocks(t1, Thread.State.WAITING);
560 >        assertThreadBlocks(t2, Thread.State.WAITING);
561 >        assertTrue(lock.isWriteLocked());
562 >        assertFalse(lock.isReadLocked());
563          releaseWriteLock(lock, s);
564          awaitTermination(t1);
565          awaitTermination(t2);
566 +        assertUnlocked(lock);
567      }
568  
569      /**
570 <     * tryReadLock succeeds if readlocked but not writelocked
570 >     * tryReadLock succeeds if read locked but not write locked
571       */
572      public void testTryLockWhenReadLocked() {
573          final StampedLock lock = new StampedLock();
# Line 507 | Line 575 | public class StampedLockTest extends JSR
575          Thread t = newStartedThread(new CheckedRunnable() {
576              public void realRun() {
577                  long rs = lock.tryReadLock();
578 <                threadAssertTrue(rs != 0L);
578 >                assertValid(lock, rs);
579                  lock.unlockRead(rs);
580              }});
581  
# Line 516 | Line 584 | public class StampedLockTest extends JSR
584      }
585  
586      /**
587 <     * tryWriteLock fails when readlocked
587 >     * tryWriteLock fails when read locked
588       */
589 <    public void testWriteTryLockWhenReadLocked() {
589 >    public void testTryWriteLockWhenReadLocked() {
590          final StampedLock lock = new StampedLock();
591          long s = lock.readLock();
592          Thread t = newStartedThread(new CheckedRunnable() {
593              public void realRun() {
594 <                long ws = lock.tryWriteLock();
527 <                threadAssertEquals(ws, 0L);
594 >                assertEquals(0L, lock.tryWriteLock());
595              }});
596  
597          awaitTermination(t);
# Line 532 | Line 599 | public class StampedLockTest extends JSR
599      }
600  
601      /**
602 <     * timed tryWriteLock times out if locked
602 >     * timed lock operations time out if lock not available
603       */
604 <    public void testWriteTryLock_Timeout() {
604 >    public void testTimedLock_Timeout() throws Exception {
605 >        ArrayList<Future<?>> futures = new ArrayList<>();
606 >
607 >        // Write locked
608          final StampedLock lock = new StampedLock();
609 <        long s = lock.writeLock();
610 <        Thread t = newStartedThread(new CheckedRunnable() {
609 >        long stamp = lock.writeLock();
610 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
611 >        assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
612 >        assertFalse(lock.asReadLock().tryLock(0L, DAYS));
613 >        assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
614 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
615 >        assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
616 >        assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
617 >        assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
618 >
619 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
620              public void realRun() throws InterruptedException {
621                  long startTime = System.nanoTime();
622 <                long timeoutMillis = 10;
623 <                long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS);
624 <                assertEquals(ws, 0L);
546 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
547 <            }});
622 >                assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
623 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
624 >            }}));
625  
626 <        awaitTermination(t);
627 <        releaseWriteLock(lock, s);
628 <    }
626 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
627 >            public void realRun() throws InterruptedException {
628 >                long startTime = System.nanoTime();
629 >                assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
630 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
631 >            }}));
632 >
633 >        // Read locked
634 >        final StampedLock lock2 = new StampedLock();
635 >        long stamp2 = lock2.readLock();
636 >        assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
637 >        assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
638 >        assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
639 >        assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
640  
641 <    /**
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() {
641 >        futures.add(cachedThreadPool.submit(new CheckedRunnable() {
642              public void realRun() throws InterruptedException {
643                  long startTime = System.nanoTime();
644 <                long timeoutMillis = 10;
645 <                long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS);
646 <                assertEquals(rs, 0L);
565 <                assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
566 <            }});
644 >                assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
645 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
646 >            }}));
647  
648 <        awaitTermination(t);
649 <        assertTrue(lock.isWriteLocked());
650 <        lock.unlockWrite(s);
648 >        for (Future<?> future : futures)
649 >            assertNull(future.get());
650 >
651 >        releaseWriteLock(lock, stamp);
652 >        releaseReadLock(lock2, stamp2);
653      }
654  
655      /**
656 <     * writeLockInterruptibly succeeds if unlocked, else is interruptible
656 >     * writeLockInterruptibly succeeds if unlocked
657       */
658      public void testWriteLockInterruptibly() throws InterruptedException {
577        final CountDownLatch running = new CountDownLatch(1);
659          final StampedLock lock = new StampedLock();
660          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();
661          assertTrue(lock.isWriteLocked());
590        awaitTermination(t);
662          releaseWriteLock(lock, s);
663      }
664  
665      /**
666 <     * readLockInterruptibly succeeds if lock free else is interruptible
666 >     * readLockInterruptibly succeeds if lock free
667       */
668      public void testReadLockInterruptibly() throws InterruptedException {
598        final CountDownLatch running = new CountDownLatch(1);
669          final StampedLock lock = new StampedLock();
670 <        long s;
671 <        s = lock.readLockInterruptibly();
670 >
671 >        long s = assertValid(lock, lock.readLockInterruptibly());
672 >        assertTrue(lock.isReadLocked());
673          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            }});
674  
675 <        running.await();
676 <        waitForThreadToEnterWaitState(t, 100);
677 <        t.interrupt();
613 <        awaitTermination(t);
614 <        releaseWriteLock(lock, s);
675 >        lock.asReadLock().lockInterruptibly();
676 >        assertTrue(lock.isReadLocked());
677 >        lock.asReadLock().unlock();
678      }
679  
680      /**
# Line 643 | Line 706 | public class StampedLockTest extends JSR
706      }
707  
708      /**
709 <     * tryOptimisticRead succeeds and validates if unlocked, fails if locked
709 >     * tryOptimisticRead succeeds and validates if unlocked, fails if
710 >     * exclusively locked
711       */
712      public void testValidateOptimistic() throws InterruptedException {
713          StampedLock lock = new StampedLock();
714 <        long s, p;
715 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
716 <        assertTrue(lock.validate(p));
717 <        assertTrue((s = lock.writeLock()) != 0L);
718 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
719 <        assertTrue(lock.validate(s));
720 <        lock.unlockWrite(s);
721 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
722 <        assertTrue(lock.validate(p));
723 <        assertTrue((s = lock.readLock()) != 0L);
724 <        assertTrue(lock.validate(s));
725 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
726 <        assertTrue(lock.validate(p));
727 <        lock.unlockRead(s);
728 <        assertTrue((s = lock.tryWriteLock()) != 0L);
729 <        assertTrue(lock.validate(s));
730 <        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);
714 >
715 >        assertValid(lock, lock.tryOptimisticRead());
716 >
717 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
718 >            long s = assertValid(lock, writeLocker.apply(lock));
719 >            assertEquals(0L, lock.tryOptimisticRead());
720 >            releaseWriteLock(lock, s);
721 >        }
722 >
723 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
724 >            long s = assertValid(lock, readLocker.apply(lock));
725 >            long p = assertValid(lock, lock.tryOptimisticRead());
726 >            releaseReadLock(lock, s);
727 >            assertTrue(lock.validate(p));
728 >        }
729 >
730 >        assertValid(lock, lock.tryOptimisticRead());
731      }
732  
733      /**
734       * tryOptimisticRead stamp does not validate if a write lock intervenes
735       */
736      public void testValidateOptimisticWriteLocked() {
737 <        StampedLock lock = new StampedLock();
738 <        long s, p;
739 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
691 <        assertTrue((s = lock.writeLock()) != 0L);
737 >        final StampedLock lock = new StampedLock();
738 >        final long p = assertValid(lock, lock.tryOptimisticRead());
739 >        final long s = assertValid(lock, lock.writeLock());
740          assertFalse(lock.validate(p));
741 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
741 >        assertEquals(0L, lock.tryOptimisticRead());
742          assertTrue(lock.validate(s));
743          lock.unlockWrite(s);
744      }
# Line 701 | Line 749 | public class StampedLockTest extends JSR
749       */
750      public void testValidateOptimisticWriteLocked2()
751              throws InterruptedException {
752 <        final CountDownLatch running = new CountDownLatch(1);
752 >        final CountDownLatch locked = new CountDownLatch(1);
753          final StampedLock lock = new StampedLock();
754 <        long s, p;
755 <        assertTrue((p = lock.tryOptimisticRead()) != 0L);
754 >        final long p = assertValid(lock, lock.tryOptimisticRead());
755 >
756          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
757              public void realRun() throws InterruptedException {
758                  lock.writeLockInterruptibly();
759 <                running.countDown();
759 >                locked.countDown();
760                  lock.writeLockInterruptibly();
761              }});
762  
763 <        running.await();
763 >        await(locked);
764          assertFalse(lock.validate(p));
765 <        assertFalse((p = lock.tryOptimisticRead()) != 0L);
765 >        assertEquals(0L, lock.tryOptimisticRead());
766 >        assertThreadBlocks(t, Thread.State.WAITING);
767          t.interrupt();
768          awaitTermination(t);
769 +        assertTrue(lock.isWriteLocked());
770      }
771  
772      /**
773 <     * tryConvertToOptimisticRead succeeds and validates if successfully locked,
773 >     * tryConvertToOptimisticRead succeeds and validates if successfully locked
774       */
775      public void testTryConvertToOptimisticRead() throws InterruptedException {
776          StampedLock lock = new StampedLock();
777 <        long s, p;
777 >        long s, p, q;
778          assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
779  
780 <        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);
780 >        s = assertValid(lock, lock.tryOptimisticRead());
781          assertEquals(s, lock.tryConvertToOptimisticRead(s));
782          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));
783  
784 <        assertTrue((s = lock.tryWriteLock()) != 0L);
785 <        assertTrue(lock.validate(s));
786 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
787 <        assertTrue(lock.validate(p));
788 <
789 <        assertTrue((s = lock.tryReadLock()) != 0L);
790 <        assertTrue(lock.validate(s));
756 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
757 <        assertTrue(lock.validate(p));
758 <
759 <        assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
760 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
761 <        assertTrue(lock.validate(p));
784 >        for (Function<StampedLock, Long> writeLocker : writeLockers()) {
785 >            s = assertValid(lock, writeLocker.apply(lock));
786 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
787 >            assertFalse(lock.validate(s));
788 >            assertTrue(lock.validate(p));
789 >            assertUnlocked(lock);
790 >        }
791  
792 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
793 <        assertTrue(lock.validate(s));
794 <        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
795 <        assertTrue(lock.validate(p));
792 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
793 >            s = assertValid(lock, readLocker.apply(lock));
794 >            q = assertValid(lock, lock.tryOptimisticRead());
795 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
796 >            assertTrue(lock.validate(q));
797 >            assertTrue(lock.isReadLocked());
798 >            p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
799 >            assertTrue(lock.validate(p));
800 >            assertTrue(lock.validate(s));
801 >            assertUnlocked(lock);
802 >            assertEquals(q, lock.tryConvertToOptimisticRead(q));
803 >            assertTrue(lock.validate(q));
804 >        }
805      }
806  
807      /**
808 <     * tryConvertToReadLock succeeds and validates if successfully locked
771 <     * or lock free;
808 >     * tryConvertToReadLock succeeds for valid stamps
809       */
810      public void testTryConvertToReadLock() throws InterruptedException {
811          StampedLock lock = new StampedLock();
812          long s, p;
813  
814 <        assertFalse((p = lock.tryConvertToReadLock(0L)) != 0L);
814 >        assertEquals(0L, lock.tryConvertToReadLock(0L));
815  
816 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
817 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
816 >        s = assertValid(lock, lock.tryOptimisticRead());
817 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
818          assertTrue(lock.isReadLocked());
819          assertEquals(1, lock.getReadLockCount());
820 +        assertTrue(lock.validate(s));
821          lock.unlockRead(p);
822  
823 <        assertTrue((s = lock.tryOptimisticRead()) != 0L);
823 >        s = assertValid(lock, lock.tryOptimisticRead());
824          lock.readLock();
825 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
825 >        p = assertValid(lock, lock.tryConvertToReadLock(s));
826          assertTrue(lock.isReadLocked());
827          assertEquals(2, lock.getReadLockCount());
828          lock.unlockRead(p);
829          lock.unlockRead(p);
830 +        assertUnlocked(lock);
831  
832 <        assertTrue((s = lock.writeLock()) != 0L);
833 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
834 <        assertTrue(lock.validate(p));
835 <        assertTrue(lock.isReadLocked());
836 <        assertEquals(1, lock.getReadLockCount());
837 <        lock.unlockRead(p);
838 <
839 <        assertTrue((s = lock.readLock()) != 0L);
840 <        assertTrue(lock.validate(s));
841 <        assertEquals(s, lock.tryConvertToReadLock(s));
842 <        assertTrue(lock.validate(s));
843 <        assertTrue(lock.isReadLocked());
844 <        assertEquals(1, lock.getReadLockCount());
845 <        lock.unlockRead(s);
846 <
847 <        assertTrue((s = lock.tryWriteLock()) != 0L);
848 <        assertTrue(lock.validate(s));
849 <        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
850 <        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);
832 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
833 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
834 >                s = assertValid(lock, writeLocker.apply(lock));
835 >                p = assertValid(lock, lock.tryConvertToReadLock(s));
836 >                assertFalse(lock.validate(s));
837 >                assertTrue(lock.isReadLocked());
838 >                assertEquals(1, lock.getReadLockCount());
839 >                readUnlocker.accept(lock, p);
840 >            }
841 >
842 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
843 >                s = assertValid(lock, readLocker.apply(lock));
844 >                assertEquals(s, lock.tryConvertToReadLock(s));
845 >                assertTrue(lock.validate(s));
846 >                assertTrue(lock.isReadLocked());
847 >                assertEquals(1, lock.getReadLockCount());
848 >                readUnlocker.accept(lock, s);
849 >            }
850 >        }
851      }
852  
853      /**
854 <     * tryConvertToWriteLock succeeds and validates if successfully locked
841 <     * or lock free;
854 >     * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
855       */
856      public void testTryConvertToWriteLock() throws InterruptedException {
857          StampedLock lock = new StampedLock();
858          long s, p;
859  
860 <        assertFalse((p = lock.tryConvertToWriteLock(0L)) != 0L);
860 >        assertEquals(0L, lock.tryConvertToWriteLock(0L));
861  
862          assertTrue((s = lock.tryOptimisticRead()) != 0L);
863          assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
864          assertTrue(lock.isWriteLocked());
865          lock.unlockWrite(p);
866  
867 <        assertTrue((s = lock.writeLock()) != 0L);
868 <        assertEquals(s, lock.tryConvertToWriteLock(s));
869 <        assertTrue(lock.validate(s));
870 <        assertTrue(lock.isWriteLocked());
871 <        lock.unlockWrite(s);
872 <
873 <        assertTrue((s = lock.readLock()) != 0L);
874 <        assertTrue(lock.validate(s));
875 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
876 <        assertTrue(lock.validate(p));
877 <        assertTrue(lock.isWriteLocked());
878 <        lock.unlockWrite(p);
879 <
880 <        assertTrue((s = lock.tryWriteLock()) != 0L);
881 <        assertTrue(lock.validate(s));
882 <        assertEquals(s, lock.tryConvertToWriteLock(s));
883 <        assertTrue(lock.validate(s));
884 <        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);
867 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
868 >            for (Function<StampedLock, Long> writeLocker : writeLockers()) {
869 >                s = assertValid(lock, writeLocker.apply(lock));
870 >                assertEquals(s, lock.tryConvertToWriteLock(s));
871 >                assertTrue(lock.validate(s));
872 >                assertTrue(lock.isWriteLocked());
873 >                writeUnlocker.accept(lock, s);
874 >            }
875 >
876 >            for (Function<StampedLock, Long> readLocker : readLockers()) {
877 >                s = assertValid(lock, readLocker.apply(lock));
878 >                p = assertValid(lock, lock.tryConvertToWriteLock(s));
879 >                assertFalse(lock.validate(s));
880 >                assertTrue(lock.validate(p));
881 >                assertTrue(lock.isWriteLocked());
882 >                writeUnlocker.accept(lock, p);
883 >            }
884 >        }
885  
886 <        assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
887 <        assertTrue(lock.validate(s));
888 <        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
889 <        assertTrue(lock.validate(p));
890 <        assertTrue(lock.isWriteLocked());
891 <        lock.unlockWrite(p);
886 >        // failure if multiply read locked
887 >        for (Function<StampedLock, Long> readLocker : readLockers()) {
888 >            s = assertValid(lock, readLocker.apply(lock));
889 >            p = assertValid(lock, readLocker.apply(lock));
890 >            assertEquals(0L, lock.tryConvertToWriteLock(s));
891 >            assertTrue(lock.validate(s));
892 >            assertTrue(lock.validate(p));
893 >            assertEquals(2, lock.getReadLockCount());
894 >            lock.unlock(p);
895 >            lock.unlock(s);
896 >            assertUnlocked(lock);
897 >        }
898      }
899  
900      /**
901       * asWriteLock can be locked and unlocked
902       */
903 <    public void testAsWriteLock() {
903 >    public void testAsWriteLock() throws Throwable {
904          StampedLock sl = new StampedLock();
905          Lock lock = sl.asWriteLock();
906 <        lock.lock();
907 <        assertFalse(lock.tryLock());
908 <        lock.unlock();
909 <        assertTrue(lock.tryLock());
906 >        for (Action locker : lockLockers(lock)) {
907 >            locker.run();
908 >            assertTrue(sl.isWriteLocked());
909 >            assertFalse(sl.isReadLocked());
910 >            assertFalse(lock.tryLock());
911 >            lock.unlock();
912 >            assertUnlocked(sl);
913 >        }
914      }
915  
916      /**
917       * asReadLock can be locked and unlocked
918       */
919 <    public void testAsReadLock() {
919 >    public void testAsReadLock() throws Throwable {
920          StampedLock sl = new StampedLock();
921          Lock lock = sl.asReadLock();
922 <        lock.lock();
923 <        lock.unlock();
924 <        assertTrue(lock.tryLock());
922 >        for (Action locker : lockLockers(lock)) {
923 >            locker.run();
924 >            assertTrue(sl.isReadLocked());
925 >            assertFalse(sl.isWriteLocked());
926 >            assertEquals(1, sl.getReadLockCount());
927 >            locker.run();
928 >            assertTrue(sl.isReadLocked());
929 >            assertEquals(2, sl.getReadLockCount());
930 >            lock.unlock();
931 >            lock.unlock();
932 >            assertUnlocked(sl);
933 >        }
934      }
935  
936      /**
937       * asReadWriteLock.writeLock can be locked and unlocked
938       */
939 <    public void testAsReadWriteLockWriteLock() {
939 >    public void testAsReadWriteLockWriteLock() throws Throwable {
940          StampedLock sl = new StampedLock();
941          Lock lock = sl.asReadWriteLock().writeLock();
942 <        lock.lock();
943 <        assertFalse(lock.tryLock());
944 <        lock.unlock();
945 <        assertTrue(lock.tryLock());
942 >        for (Action locker : lockLockers(lock)) {
943 >            locker.run();
944 >            assertTrue(sl.isWriteLocked());
945 >            assertFalse(sl.isReadLocked());
946 >            assertFalse(lock.tryLock());
947 >            lock.unlock();
948 >            assertUnlocked(sl);
949 >        }
950      }
951  
952      /**
953       * asReadWriteLock.readLock can be locked and unlocked
954       */
955 <    public void testAsReadWriteLockReadLock() {
955 >    public void testAsReadWriteLockReadLock() throws Throwable {
956          StampedLock sl = new StampedLock();
957          Lock lock = sl.asReadWriteLock().readLock();
958 <        lock.lock();
959 <        lock.unlock();
960 <        assertTrue(lock.tryLock());
958 >        for (Action locker : lockLockers(lock)) {
959 >            locker.run();
960 >            assertTrue(sl.isReadLocked());
961 >            assertFalse(sl.isWriteLocked());
962 >            assertEquals(1, sl.getReadLockCount());
963 >            locker.run();
964 >            assertTrue(sl.isReadLocked());
965 >            assertEquals(2, sl.getReadLockCount());
966 >            lock.unlock();
967 >            lock.unlock();
968 >            assertUnlocked(sl);
969 >        }
970      }
971  
972      /**
# Line 955 | Line 986 | public class StampedLockTest extends JSR
986       * IllegalMonitorStateException
987       */
988      public void testCannotUnlockOptimisticReadStamps() {
989 <        Runnable[] actions = {
990 <            () -> {
991 <                StampedLock sl = new StampedLock();
992 <                long stamp = sl.tryOptimisticRead();
993 <                assertTrue(stamp != 0);
994 <                sl.unlockRead(stamp);
995 <            },
996 <            () -> {
997 <                StampedLock sl = new StampedLock();
998 <                long stamp = sl.tryOptimisticRead();
999 <                sl.unlock(stamp);
1000 <            },
970 <
971 <            () -> {
972 <                StampedLock sl = new StampedLock();
973 <                long stamp = sl.tryOptimisticRead();
974 <                sl.writeLock();
975 <                sl.unlock(stamp);
976 <            },
977 <            () -> {
978 <                StampedLock sl = new StampedLock();
979 <                long stamp = sl.tryOptimisticRead();
980 <                sl.readLock();
981 <                sl.unlockRead(stamp);
982 <            },
983 <            () -> {
984 <                StampedLock sl = new StampedLock();
985 <                long stamp = sl.tryOptimisticRead();
986 <                sl.readLock();
987 <                sl.unlock(stamp);
988 <            },
989 >        {
990 >            StampedLock sl = new StampedLock();
991 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
992 >            assertThrows(IllegalMonitorStateException.class,
993 >                () -> sl.unlockRead(stamp));
994 >        }
995 >        {
996 >            StampedLock sl = new StampedLock();
997 >            long stamp = sl.tryOptimisticRead();
998 >            assertThrows(IllegalMonitorStateException.class,
999 >                () -> sl.unlock(stamp));
1000 >        }
1001  
1002 <            () -> {
1003 <                StampedLock sl = new StampedLock();
1004 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1005 <                assertTrue(stamp != 0);
1006 <                sl.writeLock();
1007 <                sl.unlockWrite(stamp);
1008 <            },
1009 <            () -> {
1010 <                StampedLock sl = new StampedLock();
1011 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1012 <                sl.writeLock();
1013 <                sl.unlock(stamp);
1014 <            },
1015 <            () -> {
1016 <                StampedLock sl = new StampedLock();
1017 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1018 <                sl.readLock();
1019 <                sl.unlockRead(stamp);
1020 <            },
1021 <            () -> {
1022 <                StampedLock sl = new StampedLock();
1011 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1012 <                sl.readLock();
1013 <                sl.unlock(stamp);
1014 <            },
1002 >        {
1003 >            StampedLock sl = new StampedLock();
1004 >            long stamp = sl.tryOptimisticRead();
1005 >            sl.writeLock();
1006 >            assertThrows(IllegalMonitorStateException.class,
1007 >                () -> sl.unlock(stamp));
1008 >        }
1009 >        {
1010 >            StampedLock sl = new StampedLock();
1011 >            sl.readLock();
1012 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
1013 >            assertThrows(IllegalMonitorStateException.class,
1014 >                () -> sl.unlockRead(stamp));
1015 >        }
1016 >        {
1017 >            StampedLock sl = new StampedLock();
1018 >            sl.readLock();
1019 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
1020 >            assertThrows(IllegalMonitorStateException.class,
1021 >                () -> sl.unlock(stamp));
1022 >        }
1023  
1024 <            () -> {
1025 <                StampedLock sl = new StampedLock();
1026 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1027 <                assertTrue(stamp != 0);
1028 <                sl.writeLock();
1029 <                sl.unlockWrite(stamp);
1030 <            },
1031 <            () -> {
1032 <                StampedLock sl = new StampedLock();
1033 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1034 <                sl.writeLock();
1035 <                sl.unlock(stamp);
1036 <            },
1037 <            () -> {
1038 <                StampedLock sl = new StampedLock();
1039 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1040 <                sl.readLock();
1041 <                sl.unlockRead(stamp);
1042 <            },
1043 <            () -> {
1044 <                StampedLock sl = new StampedLock();
1045 <                sl.readLock();
1046 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1047 <                assertTrue(stamp != 0);
1048 <                sl.readLock();
1049 <                sl.unlockRead(stamp);
1050 <            },
1051 <            () -> {
1052 <                StampedLock sl = new StampedLock();
1045 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1046 <                sl.readLock();
1047 <                sl.unlock(stamp);
1048 <            },
1049 <            () -> {
1050 <                StampedLock sl = new StampedLock();
1051 <                sl.readLock();
1052 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1053 <                sl.readLock();
1054 <                sl.unlock(stamp);
1055 <            },
1056 <        };
1024 >        {
1025 >            StampedLock sl = new StampedLock();
1026 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1027 >            assertValid(sl, stamp);
1028 >            sl.writeLock();
1029 >            assertThrows(IllegalMonitorStateException.class,
1030 >                () -> sl.unlockWrite(stamp));
1031 >        }
1032 >        {
1033 >            StampedLock sl = new StampedLock();
1034 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1035 >            sl.writeLock();
1036 >            assertThrows(IllegalMonitorStateException.class,
1037 >                () -> sl.unlock(stamp));
1038 >        }
1039 >        {
1040 >            StampedLock sl = new StampedLock();
1041 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1042 >            sl.readLock();
1043 >            assertThrows(IllegalMonitorStateException.class,
1044 >                () -> sl.unlockRead(stamp));
1045 >        }
1046 >        {
1047 >            StampedLock sl = new StampedLock();
1048 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1049 >            sl.readLock();
1050 >            assertThrows(IllegalMonitorStateException.class,
1051 >                () -> sl.unlock(stamp));
1052 >        }
1053  
1054 <        assertThrows(IllegalMonitorStateException.class, actions);
1054 >        {
1055 >            StampedLock sl = new StampedLock();
1056 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1057 >            assertValid(sl, stamp);
1058 >            sl.writeLock();
1059 >            assertThrows(IllegalMonitorStateException.class,
1060 >                () -> sl.unlockWrite(stamp));
1061 >            }
1062 >        {
1063 >            StampedLock sl = new StampedLock();
1064 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1065 >            sl.writeLock();
1066 >            assertThrows(IllegalMonitorStateException.class,
1067 >                () -> sl.unlock(stamp));
1068 >        }
1069 >        {
1070 >            StampedLock sl = new StampedLock();
1071 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1072 >            sl.readLock();
1073 >            assertThrows(IllegalMonitorStateException.class,
1074 >                () -> sl.unlockRead(stamp));
1075 >        }
1076 >        {
1077 >            StampedLock sl = new StampedLock();
1078 >            sl.readLock();
1079 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1080 >            assertValid(sl, stamp);
1081 >            sl.readLock();
1082 >            assertThrows(IllegalMonitorStateException.class,
1083 >                () -> sl.unlockRead(stamp));
1084 >        }
1085 >        {
1086 >            StampedLock sl = new StampedLock();
1087 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1088 >            sl.readLock();
1089 >            assertThrows(IllegalMonitorStateException.class,
1090 >                () -> sl.unlock(stamp));
1091 >        }
1092 >        {
1093 >            StampedLock sl = new StampedLock();
1094 >            sl.readLock();
1095 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1096 >            sl.readLock();
1097 >            assertThrows(IllegalMonitorStateException.class,
1098 >                () -> sl.unlock(stamp));
1099 >        }
1100      }
1101  
1102      static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
# Line 1079 | Line 1120 | public class StampedLockTest extends JSR
1120      }
1121  
1122      /**
1123 <     * Invalid write stamps result in IllegalMonitorStateException
1123 >     * Invalid stamps result in IllegalMonitorStateException
1124       */
1125 <    public void testInvalidWriteStampsThrowIllegalMonitorStateException() {
1126 <        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
1127 <        writeLockers.add((sl) -> sl.writeLock());
1128 <        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
1129 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1130 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
1131 <
1132 <        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
1133 <        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
1134 <        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
1135 <        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
1136 <        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1137 <
1138 <        List<Consumer<StampedLock>> mutaters = new ArrayList<>();
1139 <        mutaters.add((sl) -> {});
1140 <        mutaters.add((sl) -> sl.readLock());
1141 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1142 <            mutaters.add((sl) -> writeLocker.apply(sl));
1143 <
1144 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1145 <        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers)
1146 <        for (Consumer<StampedLock> mutater : mutaters) {
1147 <            final StampedLock sl = new StampedLock();
1148 <            final long stamp = writeLocker.apply(sl);
1149 <            assertTrue(stamp != 0L);
1125 >    public void testInvalidStampsThrowIllegalMonitorStateException() {
1126 >        final StampedLock sl = new StampedLock();
1127 >
1128 >        assertThrows(IllegalMonitorStateException.class,
1129 >                     () -> sl.unlockWrite(0L),
1130 >                     () -> sl.unlockRead(0L),
1131 >                     () -> sl.unlock(0L));
1132 >
1133 >        final long optimisticStamp = sl.tryOptimisticRead();
1134 >        final long readStamp = sl.readLock();
1135 >        sl.unlockRead(readStamp);
1136 >        final long writeStamp = sl.writeLock();
1137 >        sl.unlockWrite(writeStamp);
1138 >        assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1139 >        final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1140 >        final Runnable assertNoLongerValidStampsThrow = () -> {
1141 >            for (long noLongerValidStamp : noLongerValidStamps)
1142 >                assertThrows(IllegalMonitorStateException.class,
1143 >                             () -> sl.unlockWrite(noLongerValidStamp),
1144 >                             () -> sl.unlockRead(noLongerValidStamp),
1145 >                             () -> sl.unlock(noLongerValidStamp));
1146 >        };
1147 >        assertNoLongerValidStampsThrow.run();
1148 >
1149 >        for (Function<StampedLock, Long> readLocker : readLockers())
1150 >        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1151 >            final long stamp = readLocker.apply(sl);
1152 >            assertValid(sl, stamp);
1153 >            assertNoLongerValidStampsThrow.run();
1154              assertThrows(IllegalMonitorStateException.class,
1155 <                         () -> sl.unlockRead(stamp));
1156 <            writeUnlocker.accept(sl, stamp);
1157 <            mutater.accept(sl);
1155 >                         () -> sl.unlockWrite(stamp),
1156 >                         () -> sl.unlockRead(sl.tryOptimisticRead()),
1157 >                         () -> sl.unlockRead(0L));
1158 >            readUnlocker.accept(sl, stamp);
1159 >            assertUnlocked(sl);
1160 >            assertNoLongerValidStampsThrow.run();
1161 >        }
1162 >
1163 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
1164 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1165 >            final long stamp = writeLocker.apply(sl);
1166 >            assertValid(sl, stamp);
1167 >            assertNoLongerValidStampsThrow.run();
1168              assertThrows(IllegalMonitorStateException.class,
1114                         () -> sl.unlock(stamp),
1169                           () -> sl.unlockRead(stamp),
1170 <                         () -> sl.unlockWrite(stamp));
1170 >                         () -> sl.unlockWrite(0L));
1171 >            writeUnlocker.accept(sl, stamp);
1172 >            assertUnlocked(sl);
1173 >            assertNoLongerValidStampsThrow.run();
1174 >        }
1175 >    }
1176 >
1177 >    /**
1178 >     * Read locks can be very deeply nested
1179 >     */
1180 >    public void testDeeplyNestedReadLocks() {
1181 >        final StampedLock lock = new StampedLock();
1182 >        final int depth = 300;
1183 >        final long[] stamps = new long[depth];
1184 >        final List<Function<StampedLock, Long>> readLockers = readLockers();
1185 >        final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1186 >        for (int i = 0; i < depth; i++) {
1187 >            Function<StampedLock, Long> readLocker
1188 >                = readLockers.get(i % readLockers.size());
1189 >            long stamp = readLocker.apply(lock);
1190 >            assertEquals(i + 1, lock.getReadLockCount());
1191 >            assertTrue(lock.isReadLocked());
1192 >            stamps[i] = stamp;
1193 >        }
1194 >        for (int i = 0; i < depth; i++) {
1195 >            BiConsumer<StampedLock, Long> readUnlocker
1196 >                = readUnlockers.get(i % readUnlockers.size());
1197 >            assertEquals(depth - i, lock.getReadLockCount());
1198 >            assertTrue(lock.isReadLocked());
1199 >            readUnlocker.accept(lock, stamps[depth - 1 - i]);
1200          }
1201 +        assertUnlocked(lock);
1202      }
1203  
1204      /**
1205 <     * Invalid read stamps result in IllegalMonitorStateException
1205 >     * Stamped locks are not reentrant.
1206       */
1207 <    public void testInvalidReadStampsThrowIllegalMonitorStateException() {
1208 <        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
1209 <        readLockers.add((sl) -> sl.readLock());
1126 <        readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
1127 <        readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1128 <        readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0, DAYS));
1207 >    public void testNonReentrant() throws InterruptedException {
1208 >        final StampedLock lock = new StampedLock();
1209 >        long stamp;
1210  
1211 <        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
1212 <        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
1213 <        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
1214 <        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
1215 <        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1211 >        stamp = lock.writeLock();
1212 >        assertValid(lock, stamp);
1213 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1214 >        assertEquals(0L, lock.tryReadLock(0L, DAYS));
1215 >        assertValid(lock, stamp);
1216 >        lock.unlockWrite(stamp);
1217 >
1218 >        stamp = lock.tryWriteLock(1L, DAYS);
1219 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1220 >        assertValid(lock, stamp);
1221 >        lock.unlockWrite(stamp);
1222 >
1223 >        stamp = lock.readLock();
1224 >        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1225 >        assertValid(lock, stamp);
1226 >        lock.unlockRead(stamp);
1227 >    }
1228  
1229 <        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
1230 <        writeLockers.add((sl) -> sl.writeLock());
1231 <        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
1232 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
1233 <        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
1229 >    /**
1230 >     * """StampedLocks have no notion of ownership. Locks acquired in
1231 >     * one thread can be released or converted in another."""
1232 >     */
1233 >    public void testNoOwnership() throws Throwable {
1234 >        ArrayList<Future<?>> futures = new ArrayList<>();
1235 >        for (Function<StampedLock, Long> writeLocker : writeLockers())
1236 >        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1237 >            StampedLock lock = new StampedLock();
1238 >            long stamp = writeLocker.apply(lock);
1239 >            futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1240 >                public void realRun() {
1241 >                    writeUnlocker.accept(lock, stamp);
1242 >                    assertUnlocked(lock);
1243 >                    assertFalse(lock.validate(stamp));
1244 >                }}));
1245 >        }
1246 >        for (Future<?> future : futures)
1247 >            assertNull(future.get());
1248 >    }
1249  
1250 <        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
1251 <        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
1252 <        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
1253 <        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
1254 <        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
1250 >    /** Tries out sample usage code from StampedLock javadoc. */
1251 >    public void testSampleUsage() throws Throwable {
1252 >        class Point {
1253 >            private double x, y;
1254 >            private final StampedLock sl = new StampedLock();
1255 >
1256 >            void move(double deltaX, double deltaY) { // an exclusively locked method
1257 >                long stamp = sl.writeLock();
1258 >                try {
1259 >                    x += deltaX;
1260 >                    y += deltaY;
1261 >                } finally {
1262 >                    sl.unlockWrite(stamp);
1263 >                }
1264 >            }
1265  
1266 +            double distanceFromOrigin() { // A read-only method
1267 +                double currentX, currentY;
1268 +                long stamp = sl.tryOptimisticRead();
1269 +                do {
1270 +                    if (stamp == 0L)
1271 +                        stamp = sl.readLock();
1272 +                    try {
1273 +                        // possibly racy reads
1274 +                        currentX = x;
1275 +                        currentY = y;
1276 +                    } finally {
1277 +                        stamp = sl.tryConvertToOptimisticRead(stamp);
1278 +                    }
1279 +                } while (stamp == 0);
1280 +                return Math.hypot(currentX, currentY);
1281 +            }
1282  
1283 <        for (Function<StampedLock, Long> readLocker : readLockers)
1284 <        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers)
1285 <        for (Function<StampedLock, Long> writeLocker : writeLockers)
1286 <        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers) {
1287 <            final StampedLock sl = new StampedLock();
1288 <            final long stamp = readLocker.apply(sl);
1289 <            assertTrue(stamp != 0L);
1290 <            assertThrows(IllegalMonitorStateException.class,
1291 <                         () -> sl.unlockWrite(stamp));
1292 <            readUnlocker.accept(sl, stamp);
1293 <            assertThrows(IllegalMonitorStateException.class,
1294 <                         () -> sl.unlock(stamp),
1295 <                         () -> sl.unlockRead(stamp),
1296 <                         () -> sl.unlockWrite(stamp));
1297 <            final long writeStamp = writeLocker.apply(sl);
1298 <            assertTrue(writeStamp != 0L);
1299 <            assertTrue(writeStamp != stamp);
1300 <            assertThrows(IllegalMonitorStateException.class,
1301 <                         () -> sl.unlock(stamp),
1302 <                         () -> sl.unlockRead(stamp),
1303 <                         () -> sl.unlockWrite(stamp));
1304 <            writeUnlocker.accept(sl, writeStamp);
1305 <            assertThrows(IllegalMonitorStateException.class,
1306 <                         () -> sl.unlock(stamp),
1307 <                         () -> sl.unlockRead(stamp),
1308 <                         () -> sl.unlockWrite(stamp));
1283 >            double distanceFromOrigin2() {
1284 >                long stamp = sl.tryOptimisticRead();
1285 >                try {
1286 >                    retryHoldingLock:
1287 >                    for (;; stamp = sl.readLock()) {
1288 >                        if (stamp == 0L)
1289 >                            continue retryHoldingLock;
1290 >                        // possibly racy reads
1291 >                        double currentX = x;
1292 >                        double currentY = y;
1293 >                        if (!sl.validate(stamp))
1294 >                            continue retryHoldingLock;
1295 >                        return Math.hypot(currentX, currentY);
1296 >                    }
1297 >                } finally {
1298 >                    if (StampedLock.isReadLockStamp(stamp))
1299 >                        sl.unlockRead(stamp);
1300 >                }
1301 >            }
1302 >
1303 >            void moveIfAtOrigin(double newX, double newY) {
1304 >                long stamp = sl.readLock();
1305 >                try {
1306 >                    while (x == 0.0 && y == 0.0) {
1307 >                        long ws = sl.tryConvertToWriteLock(stamp);
1308 >                        if (ws != 0L) {
1309 >                            stamp = ws;
1310 >                            x = newX;
1311 >                            y = newY;
1312 >                            return;
1313 >                        }
1314 >                        else {
1315 >                            sl.unlockRead(stamp);
1316 >                            stamp = sl.writeLock();
1317 >                        }
1318 >                    }
1319 >                } finally {
1320 >                    sl.unlock(stamp);
1321 >                }
1322 >            }
1323 >        }
1324 >
1325 >        Point p = new Point();
1326 >        p.move(3.0, 4.0);
1327 >        assertEquals(5.0, p.distanceFromOrigin());
1328 >        p.moveIfAtOrigin(5.0, 12.0);
1329 >        assertEquals(5.0, p.distanceFromOrigin2());
1330 >    }
1331 >
1332 >    /**
1333 >     * Stamp inspection methods work as expected, and do not inspect
1334 >     * the state of the lock itself.
1335 >     */
1336 >    public void testStampStateInspectionMethods() {
1337 >        StampedLock lock = new StampedLock();
1338 >
1339 >        assertFalse(isWriteLockStamp(0L));
1340 >        assertFalse(isReadLockStamp(0L));
1341 >        assertFalse(isLockStamp(0L));
1342 >        assertFalse(isOptimisticReadStamp(0L));
1343 >
1344 >        {
1345 >            long stamp = lock.writeLock();
1346 >            for (int i = 0; i < 2; i++) {
1347 >                assertTrue(isWriteLockStamp(stamp));
1348 >                assertFalse(isReadLockStamp(stamp));
1349 >                assertTrue(isLockStamp(stamp));
1350 >                assertFalse(isOptimisticReadStamp(stamp));
1351 >                if (i == 0)
1352 >                    lock.unlockWrite(stamp);
1353 >            }
1354 >        }
1355 >
1356 >        {
1357 >            long stamp = lock.readLock();
1358 >            for (int i = 0; i < 2; i++) {
1359 >                assertFalse(isWriteLockStamp(stamp));
1360 >                assertTrue(isReadLockStamp(stamp));
1361 >                assertTrue(isLockStamp(stamp));
1362 >                assertFalse(isOptimisticReadStamp(stamp));
1363 >                if (i == 0)
1364 >                    lock.unlockRead(stamp);
1365 >            }
1366 >        }
1367 >
1368 >        {
1369 >            long optimisticStamp = lock.tryOptimisticRead();
1370 >            long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1371 >            long writeStamp = lock.tryConvertToWriteLock(readStamp);
1372 >            for (int i = 0; i < 2; i++) {
1373 >                assertFalse(isWriteLockStamp(optimisticStamp));
1374 >                assertFalse(isReadLockStamp(optimisticStamp));
1375 >                assertFalse(isLockStamp(optimisticStamp));
1376 >                assertTrue(isOptimisticReadStamp(optimisticStamp));
1377 >
1378 >                assertFalse(isWriteLockStamp(readStamp));
1379 >                assertTrue(isReadLockStamp(readStamp));
1380 >                assertTrue(isLockStamp(readStamp));
1381 >                assertFalse(isOptimisticReadStamp(readStamp));
1382 >
1383 >                assertTrue(isWriteLockStamp(writeStamp));
1384 >                assertFalse(isReadLockStamp(writeStamp));
1385 >                assertTrue(isLockStamp(writeStamp));
1386 >                assertFalse(isOptimisticReadStamp(writeStamp));
1387 >                if (i == 0)
1388 >                    lock.unlockWrite(writeStamp);
1389 >            }
1390 >        }
1391 >    }
1392 >
1393 >    /**
1394 >     * Multiple threads repeatedly contend for the same lock.
1395 >     */
1396 >    public void testConcurrentAccess() throws Exception {
1397 >        final StampedLock sl = new StampedLock();
1398 >        final Lock wl = sl.asWriteLock();
1399 >        final Lock rl = sl.asReadLock();
1400 >        final long testDurationMillis = expensiveTests ? 1000 : 2;
1401 >        final int nTasks = ThreadLocalRandom.current().nextInt(1, 10);
1402 >        final AtomicBoolean done = new AtomicBoolean(false);
1403 >        final List<CompletableFuture> futures = new ArrayList<>();
1404 >        final List<Callable<Long>> stampedWriteLockers = List.of(
1405 >            () -> sl.writeLock(),
1406 >            () -> writeLockInterruptiblyUninterrupted(sl),
1407 >            () -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1408 >            () -> {
1409 >                long stamp;
1410 >                do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); }
1411 >                while (stamp == 0L);
1412 >                return stamp;
1413 >            },
1414 >            () -> {
1415 >              long stamp;
1416 >              do { stamp = sl.tryWriteLock(); } while (stamp == 0L);
1417 >              return stamp;
1418 >            },
1419 >            () -> {
1420 >              long stamp;
1421 >              do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L);
1422 >              return stamp;
1423 >            });
1424 >        final List<Callable<Long>> stampedReadLockers = List.of(
1425 >            () -> sl.readLock(),
1426 >            () -> readLockInterruptiblyUninterrupted(sl),
1427 >            () -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1428 >            () -> {
1429 >                long stamp;
1430 >                do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); }
1431 >                while (stamp == 0L);
1432 >                return stamp;
1433 >            },
1434 >            () -> {
1435 >              long stamp;
1436 >              do { stamp = sl.tryReadLock(); } while (stamp == 0L);
1437 >              return stamp;
1438 >            },
1439 >            () -> {
1440 >              long stamp;
1441 >              do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L);
1442 >              return stamp;
1443 >            });
1444 >        final List<Consumer<Long>> stampedWriteUnlockers = List.of(
1445 >            stamp -> sl.unlockWrite(stamp),
1446 >            stamp -> sl.unlock(stamp),
1447 >            stamp -> assertTrue(sl.tryUnlockWrite()),
1448 >            stamp -> wl.unlock(),
1449 >            stamp -> sl.tryConvertToOptimisticRead(stamp));
1450 >        final List<Consumer<Long>> stampedReadUnlockers = List.of(
1451 >            stamp -> sl.unlockRead(stamp),
1452 >            stamp -> sl.unlock(stamp),
1453 >            stamp -> assertTrue(sl.tryUnlockRead()),
1454 >            stamp -> rl.unlock(),
1455 >            stamp -> sl.tryConvertToOptimisticRead(stamp));
1456 >        final Action writer = () -> {
1457 >            // repeatedly acquires write lock
1458 >            var locker = chooseRandomly(stampedWriteLockers);
1459 >            var unlocker = chooseRandomly(stampedWriteUnlockers);
1460 >            while (!done.getAcquire()) {
1461 >                long stamp = locker.call();
1462 >                try {
1463 >                    assertTrue(isWriteLockStamp(stamp));
1464 >                    assertTrue(sl.isWriteLocked());
1465 >                    assertFalse(isReadLockStamp(stamp));
1466 >                    assertFalse(sl.isReadLocked());
1467 >                    assertEquals(0, sl.getReadLockCount());
1468 >                    assertTrue(sl.validate(stamp));
1469 >                } finally {
1470 >                    unlocker.accept(stamp);
1471 >                }
1472 >            }
1473 >        };
1474 >        final Action reader = () -> {
1475 >            // repeatedly acquires read lock
1476 >            var locker = chooseRandomly(stampedReadLockers);
1477 >            var unlocker = chooseRandomly(stampedReadUnlockers);
1478 >            while (!done.getAcquire()) {
1479 >                long stamp = locker.call();
1480 >                try {
1481 >                    assertFalse(isWriteLockStamp(stamp));
1482 >                    assertFalse(sl.isWriteLocked());
1483 >                    assertTrue(isReadLockStamp(stamp));
1484 >                    assertTrue(sl.isReadLocked());
1485 >                    assertTrue(sl.getReadLockCount() > 0);
1486 >                    assertTrue(sl.validate(stamp));
1487 >                } finally {
1488 >                    unlocker.accept(stamp);
1489 >                }
1490 >            }
1491 >        };
1492 >        for (int i = nTasks; i--> 0; ) {
1493 >            Action task = chooseRandomly(writer, reader);
1494 >            futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
1495          }
1496 +        Thread.sleep(testDurationMillis);
1497 +        done.setRelease(true);
1498 +        for (var future : futures)
1499 +            checkTimedGet(future, null);
1500      }
1501  
1502   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines