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.21 by jsr166, Tue Jun 7 22:10:33 2016 UTC vs.
Revision 1.34 by jsr166, Sat Mar 25 21:41:10 2017 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines