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