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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines