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