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         Runnable[] actions = {
1013             () -> {
1014                 StampedLock sl = new StampedLock();
1015                 long stamp = assertValid(sl, sl.tryOptimisticRead());
1016                 sl.unlockRead(stamp);
1017             },
1018             () -> {
1019                 StampedLock sl = new StampedLock();
1020                 long stamp = sl.tryOptimisticRead();
1021                 sl.unlock(stamp);
1022             },
1023 
1024             () -> {
1025                 StampedLock sl = new StampedLock();
1026                 long stamp = sl.tryOptimisticRead();
1027                 sl.writeLock();
1028                 sl.unlock(stamp);
1029             },
1030             () -> {
1031                 StampedLock sl = new StampedLock();
1032                 sl.readLock();
1033                 long stamp = assertValid(sl, sl.tryOptimisticRead());
1034                 sl.unlockRead(stamp);
1035             },
1036             () -> {
1037                 StampedLock sl = new StampedLock();
1038                 sl.readLock();
1039                 long stamp = assertValid(sl, sl.tryOptimisticRead());
1040                 sl.unlock(stamp);
1041             },
1042 
1043             () -> {
1044                 StampedLock sl = new StampedLock();
1045                 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1046                 assertValid(sl, stamp);
1047                 sl.writeLock();
1048                 sl.unlockWrite(stamp);
1049             },
1050             () -> {
1051                 StampedLock sl = new StampedLock();
1052                 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1053                 sl.writeLock();
1054                 sl.unlock(stamp);
1055             },
1056             () -> {
1057                 StampedLock sl = new StampedLock();
1058                 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1059                 sl.readLock();
1060                 sl.unlockRead(stamp);
1061             },
1062             () -> {
1063                 StampedLock sl = new StampedLock();
1064                 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1065                 sl.readLock();
1066                 sl.unlock(stamp);
1067             },
1068 
1069             () -> {
1070                 StampedLock sl = new StampedLock();
1071                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1072                 assertValid(sl, stamp);
1073                 sl.writeLock();
1074                 sl.unlockWrite(stamp);
1075             },
1076             () -> {
1077                 StampedLock sl = new StampedLock();
1078                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1079                 sl.writeLock();
1080                 sl.unlock(stamp);
1081             },
1082             () -> {
1083                 StampedLock sl = new StampedLock();
1084                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1085                 sl.readLock();
1086                 sl.unlockRead(stamp);
1087             },
1088             () -> {
1089                 StampedLock sl = new StampedLock();
1090                 sl.readLock();
1091                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1092                 assertValid(sl, stamp);
1093                 sl.readLock();
1094                 sl.unlockRead(stamp);
1095             },
1096             () -> {
1097                 StampedLock sl = new StampedLock();
1098                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1099                 sl.readLock();
1100                 sl.unlock(stamp);
1101             },
1102             () -> {
1103                 StampedLock sl = new StampedLock();
1104                 sl.readLock();
1105                 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1106                 sl.readLock();
1107                 sl.unlock(stamp);
1108             },
1109         };
1110 
1111         assertThrows(IllegalMonitorStateException.class, actions);
1112     }
1113 
writeLockInterruptiblyUninterrupted(StampedLock sl)1114     static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
1115         try { return sl.writeLockInterruptibly(); }
1116         catch (InterruptedException ex) { throw new AssertionError(ex); }
1117     }
1118 
tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit)1119     static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1120         try { return sl.tryWriteLock(time, unit); }
1121         catch (InterruptedException ex) { throw new AssertionError(ex); }
1122     }
1123 
readLockInterruptiblyUninterrupted(StampedLock sl)1124     static long readLockInterruptiblyUninterrupted(StampedLock sl) {
1125         try { return sl.readLockInterruptibly(); }
1126         catch (InterruptedException ex) { throw new AssertionError(ex); }
1127     }
1128 
tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit)1129     static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1130         try { return sl.tryReadLock(time, unit); }
1131         catch (InterruptedException ex) { throw new AssertionError(ex); }
1132     }
1133 
1134     /**
1135      * Invalid stamps result in IllegalMonitorStateException
1136      */
testInvalidStampsThrowIllegalMonitorStateException()1137     public void testInvalidStampsThrowIllegalMonitorStateException() {
1138         final StampedLock sl = new StampedLock();
1139 
1140         assertThrows(IllegalMonitorStateException.class,
1141                      () -> sl.unlockWrite(0L),
1142                      () -> sl.unlockRead(0L),
1143                      () -> sl.unlock(0L));
1144 
1145         final long optimisticStamp = sl.tryOptimisticRead();
1146         final long readStamp = sl.readLock();
1147         sl.unlockRead(readStamp);
1148         final long writeStamp = sl.writeLock();
1149         sl.unlockWrite(writeStamp);
1150         assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1151         final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1152         final Runnable assertNoLongerValidStampsThrow = () -> {
1153             for (long noLongerValidStamp : noLongerValidStamps)
1154                 assertThrows(IllegalMonitorStateException.class,
1155                              () -> sl.unlockWrite(noLongerValidStamp),
1156                              () -> sl.unlockRead(noLongerValidStamp),
1157                              () -> sl.unlock(noLongerValidStamp));
1158         };
1159         assertNoLongerValidStampsThrow.run();
1160 
1161         for (Function<StampedLock, Long> readLocker : readLockers())
1162         for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1163             final long stamp = readLocker.apply(sl);
1164             assertValid(sl, stamp);
1165             assertNoLongerValidStampsThrow.run();
1166             assertThrows(IllegalMonitorStateException.class,
1167                          () -> sl.unlockWrite(stamp),
1168                          () -> sl.unlockRead(sl.tryOptimisticRead()),
1169                          () -> sl.unlockRead(0L));
1170             readUnlocker.accept(sl, stamp);
1171             assertUnlocked(sl);
1172             assertNoLongerValidStampsThrow.run();
1173         }
1174 
1175         for (Function<StampedLock, Long> writeLocker : writeLockers())
1176         for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1177             final long stamp = writeLocker.apply(sl);
1178             assertValid(sl, stamp);
1179             assertNoLongerValidStampsThrow.run();
1180             assertThrows(IllegalMonitorStateException.class,
1181                          () -> sl.unlockRead(stamp),
1182                          () -> sl.unlockWrite(0L));
1183             writeUnlocker.accept(sl, stamp);
1184             assertUnlocked(sl);
1185             assertNoLongerValidStampsThrow.run();
1186         }
1187     }
1188 
1189     /**
1190      * Read locks can be very deeply nested
1191      */
testDeeplyNestedReadLocks()1192     public void testDeeplyNestedReadLocks() {
1193         final StampedLock lock = new StampedLock();
1194         final int depth = 300;
1195         final long[] stamps = new long[depth];
1196         final List<Function<StampedLock, Long>> readLockers = readLockers();
1197         final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1198         for (int i = 0; i < depth; i++) {
1199             Function<StampedLock, Long> readLocker
1200                 = readLockers.get(i % readLockers.size());
1201             long stamp = readLocker.apply(lock);
1202             assertEquals(i + 1, lock.getReadLockCount());
1203             assertTrue(lock.isReadLocked());
1204             stamps[i] = stamp;
1205         }
1206         for (int i = 0; i < depth; i++) {
1207             BiConsumer<StampedLock, Long> readUnlocker
1208                 = readUnlockers.get(i % readUnlockers.size());
1209             assertEquals(depth - i, lock.getReadLockCount());
1210             assertTrue(lock.isReadLocked());
1211             readUnlocker.accept(lock, stamps[depth - 1 - i]);
1212         }
1213         assertUnlocked(lock);
1214     }
1215 
1216     /**
1217      * Stamped locks are not reentrant.
1218      */
testNonReentrant()1219     public void testNonReentrant() throws InterruptedException {
1220         final StampedLock lock = new StampedLock();
1221         long stamp;
1222 
1223         stamp = lock.writeLock();
1224         assertValid(lock, stamp);
1225         assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1226         assertEquals(0L, lock.tryReadLock(0L, DAYS));
1227         assertValid(lock, stamp);
1228         lock.unlockWrite(stamp);
1229 
1230         stamp = lock.tryWriteLock(1L, DAYS);
1231         assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1232         assertValid(lock, stamp);
1233         lock.unlockWrite(stamp);
1234 
1235         stamp = lock.readLock();
1236         assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1237         assertValid(lock, stamp);
1238         lock.unlockRead(stamp);
1239     }
1240 
1241     /**
1242      * """StampedLocks have no notion of ownership. Locks acquired in
1243      * one thread can be released or converted in another."""
1244      */
testNoOwnership()1245     public void testNoOwnership() throws Throwable {
1246         ArrayList<Future<?>> futures = new ArrayList<>();
1247         for (Function<StampedLock, Long> writeLocker : writeLockers())
1248         for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1249             StampedLock lock = new StampedLock();
1250             long stamp = writeLocker.apply(lock);
1251             futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1252                 public void realRun() {
1253                     writeUnlocker.accept(lock, stamp);
1254                     assertUnlocked(lock);
1255                     assertFalse(lock.validate(stamp));
1256                 }}));
1257         }
1258         for (Future<?> future : futures)
1259             assertNull(future.get());
1260     }
1261 
1262     /** Tries out sample usage code from StampedLock javadoc. */
testSampleUsage()1263     public void testSampleUsage() throws Throwable {
1264         class Point {
1265             private double x, y;
1266             private final StampedLock sl = new StampedLock();
1267 
1268             void move(double deltaX, double deltaY) { // an exclusively locked method
1269                 long stamp = sl.writeLock();
1270                 try {
1271                     x += deltaX;
1272                     y += deltaY;
1273                 } finally {
1274                     sl.unlockWrite(stamp);
1275                 }
1276             }
1277 
1278             double distanceFromOrigin() { // A read-only method
1279                 double currentX, currentY;
1280                 long stamp = sl.tryOptimisticRead();
1281                 do {
1282                     if (stamp == 0L)
1283                         stamp = sl.readLock();
1284                     try {
1285                         // possibly racy reads
1286                         currentX = x;
1287                         currentY = y;
1288                     } finally {
1289                         stamp = sl.tryConvertToOptimisticRead(stamp);
1290                     }
1291                 } while (stamp == 0);
1292                 return Math.hypot(currentX, currentY);
1293             }
1294 
1295             double distanceFromOrigin2() {
1296                 long stamp = sl.tryOptimisticRead();
1297                 try {
1298                     retryHoldingLock:
1299                     for (;; stamp = sl.readLock()) {
1300                         if (stamp == 0L)
1301                             continue retryHoldingLock;
1302                         // possibly racy reads
1303                         double currentX = x;
1304                         double currentY = y;
1305                         if (!sl.validate(stamp))
1306                             continue retryHoldingLock;
1307                         return Math.hypot(currentX, currentY);
1308                     }
1309                 } finally {
1310                     if (StampedLock.isReadLockStamp(stamp))
1311                         sl.unlockRead(stamp);
1312                 }
1313             }
1314 
1315             void moveIfAtOrigin(double newX, double newY) {
1316                 long stamp = sl.readLock();
1317                 try {
1318                     while (x == 0.0 && y == 0.0) {
1319                         long ws = sl.tryConvertToWriteLock(stamp);
1320                         if (ws != 0L) {
1321                             stamp = ws;
1322                             x = newX;
1323                             y = newY;
1324                             return;
1325                         }
1326                         else {
1327                             sl.unlockRead(stamp);
1328                             stamp = sl.writeLock();
1329                         }
1330                     }
1331                 } finally {
1332                     sl.unlock(stamp);
1333                 }
1334             }
1335         }
1336 
1337         Point p = new Point();
1338         p.move(3.0, 4.0);
1339         assertEquals(5.0, p.distanceFromOrigin());
1340         p.moveIfAtOrigin(5.0, 12.0);
1341         assertEquals(5.0, p.distanceFromOrigin2());
1342     }
1343 
1344     /**
1345      * Stamp inspection methods work as expected, and do not inspect
1346      * the state of the lock itself.
1347      */
testStampStateInspectionMethods()1348     public void testStampStateInspectionMethods() {
1349         StampedLock lock = new StampedLock();
1350 
1351         assertFalse(isWriteLockStamp(0L));
1352         assertFalse(isReadLockStamp(0L));
1353         assertFalse(isLockStamp(0L));
1354         assertFalse(isOptimisticReadStamp(0L));
1355 
1356         {
1357             long stamp = lock.writeLock();
1358             for (int i = 0; i < 2; i++) {
1359                 assertTrue(isWriteLockStamp(stamp));
1360                 assertFalse(isReadLockStamp(stamp));
1361                 assertTrue(isLockStamp(stamp));
1362                 assertFalse(isOptimisticReadStamp(stamp));
1363                 if (i == 0)
1364                     lock.unlockWrite(stamp);
1365             }
1366         }
1367 
1368         {
1369             long stamp = lock.readLock();
1370             for (int i = 0; i < 2; i++) {
1371                 assertFalse(isWriteLockStamp(stamp));
1372                 assertTrue(isReadLockStamp(stamp));
1373                 assertTrue(isLockStamp(stamp));
1374                 assertFalse(isOptimisticReadStamp(stamp));
1375                 if (i == 0)
1376                     lock.unlockRead(stamp);
1377             }
1378         }
1379 
1380         {
1381             long optimisticStamp = lock.tryOptimisticRead();
1382             long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1383             long writeStamp = lock.tryConvertToWriteLock(readStamp);
1384             for (int i = 0; i < 2; i++) {
1385                 assertFalse(isWriteLockStamp(optimisticStamp));
1386                 assertFalse(isReadLockStamp(optimisticStamp));
1387                 assertFalse(isLockStamp(optimisticStamp));
1388                 assertTrue(isOptimisticReadStamp(optimisticStamp));
1389 
1390                 assertFalse(isWriteLockStamp(readStamp));
1391                 assertTrue(isReadLockStamp(readStamp));
1392                 assertTrue(isLockStamp(readStamp));
1393                 assertFalse(isOptimisticReadStamp(readStamp));
1394 
1395                 assertTrue(isWriteLockStamp(writeStamp));
1396                 assertFalse(isReadLockStamp(writeStamp));
1397                 assertTrue(isLockStamp(writeStamp));
1398                 assertFalse(isOptimisticReadStamp(writeStamp));
1399                 if (i == 0)
1400                     lock.unlockWrite(writeStamp);
1401             }
1402         }
1403     }
1404 
1405 }
1406