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.4 by dl, Wed Mar 20 16:51:11 2013 UTC vs.
Revision 1.36 by jsr166, Mon May 29 19:15:03 2017 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines