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.44 by jsr166, Sun Sep 29 20:19:43 2019 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines