ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
(Generate patch)

Comparing jsr166/src/test/tck/StampedLockTest.java (file contents):
Revision 1.30 by jsr166, Sat Feb 18 00:32:30 2017 UTC vs.
Revision 1.45 by jsr166, Wed Aug 12 16:12:23 2020 UTC

# Line 7 | Line 7
7  
8   import static java.util.concurrent.TimeUnit.DAYS;
9   import static java.util.concurrent.TimeUnit.MILLISECONDS;
10 < import static java.util.concurrent.TimeUnit.SECONDS;
10 >
11 > import static java.util.concurrent.locks.StampedLock.isLockStamp;
12 > import static java.util.concurrent.locks.StampedLock.isOptimisticReadStamp;
13 > import static java.util.concurrent.locks.StampedLock.isReadLockStamp;
14 > import static java.util.concurrent.locks.StampedLock.isWriteLockStamp;
15  
16   import java.util.ArrayList;
17   import java.util.List;
18 + import java.util.concurrent.Callable;
19 + import java.util.concurrent.CompletableFuture;
20   import java.util.concurrent.CountDownLatch;
21   import java.util.concurrent.Future;
22 + import java.util.concurrent.ThreadLocalRandom;
23   import java.util.concurrent.TimeUnit;
24 + import java.util.concurrent.atomic.AtomicBoolean;
25   import java.util.concurrent.locks.Lock;
26   import java.util.concurrent.locks.StampedLock;
27   import java.util.function.BiConsumer;
28 + import java.util.function.Consumer;
29   import java.util.function.Function;
30  
31   import junit.framework.Test;
# Line 71 | Line 80 | public class StampedLockTest extends JSR
80      }
81  
82      List<Action> lockLockers(Lock lock) {
83 <        List<Action> lockers = new ArrayList<>();
84 <        lockers.add(() -> lock.lock());
85 <        lockers.add(() -> lock.lockInterruptibly());
86 <        lockers.add(() -> lock.tryLock());
87 <        lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS));
88 <        lockers.add(() -> lock.tryLock(0L, DAYS));
89 <        lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS));
81 <        return lockers;
83 >        return List.of(
84 >            () -> lock.lock(),
85 >            () -> lock.lockInterruptibly(),
86 >            () -> lock.tryLock(),
87 >            () -> lock.tryLock(Long.MIN_VALUE, DAYS),
88 >            () -> lock.tryLock(0L, DAYS),
89 >            () -> lock.tryLock(Long.MAX_VALUE, DAYS));
90      }
91  
92      List<Function<StampedLock, Long>> readLockers() {
93 <        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
94 <        readLockers.add(sl -> sl.readLock());
95 <        readLockers.add(sl -> sl.tryReadLock());
96 <        readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
97 <        readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
98 <        readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
99 <        readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
92 <        return readLockers;
93 >        return List.of(
94 >            sl -> sl.readLock(),
95 >            sl -> sl.tryReadLock(),
96 >            sl -> readLockInterruptiblyUninterrupted(sl),
97 >            sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS),
98 >            sl -> tryReadLockUninterrupted(sl, 0L, DAYS),
99 >            sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
100      }
101  
102      List<BiConsumer<StampedLock, Long>> readUnlockers() {
103 <        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
104 <        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
105 <        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
106 <        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
107 <        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
108 <        readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
102 <        return readUnlockers;
103 >        return List.of(
104 >            (sl, stamp) -> sl.unlockRead(stamp),
105 >            (sl, stamp) -> assertTrue(sl.tryUnlockRead()),
106 >            (sl, stamp) -> sl.asReadLock().unlock(),
107 >            (sl, stamp) -> sl.unlock(stamp),
108 >            (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
109      }
110  
111      List<Function<StampedLock, Long>> writeLockers() {
112 <        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
113 <        writeLockers.add(sl -> sl.writeLock());
114 <        writeLockers.add(sl -> sl.tryWriteLock());
115 <        writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
116 <        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
117 <        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
118 <        writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
113 <        return writeLockers;
112 >        return List.of(
113 >            sl -> sl.writeLock(),
114 >            sl -> sl.tryWriteLock(),
115 >            sl -> writeLockInterruptiblyUninterrupted(sl),
116 >            sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS),
117 >            sl -> tryWriteLockUninterrupted(sl, 0L, DAYS),
118 >            sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
119      }
120  
121      List<BiConsumer<StampedLock, Long>> writeUnlockers() {
122 <        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
123 <        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
124 <        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
125 <        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
126 <        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
127 <        writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
123 <        return writeUnlockers;
122 >        return List.of(
123 >            (sl, stamp) -> sl.unlockWrite(stamp),
124 >            (sl, stamp) -> assertTrue(sl.tryUnlockWrite()),
125 >            (sl, stamp) -> sl.asWriteLock().unlock(),
126 >            (sl, stamp) -> sl.unlock(stamp),
127 >            (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
128      }
129  
130      /**
# Line 248 | Line 252 | public class StampedLockTest extends JSR
252          long s = assertNonZero(lock.writeLock());
253          assertTrue(lock.validate(s));
254          assertFalse(lock.validate(lock.tryWriteLock()));
255 <        assertFalse(lock.validate(lock.tryWriteLock(0L, SECONDS)));
255 >        assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(),
256 >                                                    randomTimeUnit())));
257          assertFalse(lock.validate(lock.tryReadLock()));
258 <        assertFalse(lock.validate(lock.tryReadLock(0L, SECONDS)));
258 >        assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(),
259 >                                                    randomTimeUnit())));
260          assertFalse(lock.validate(lock.tryOptimisticRead()));
261          lock.unlockWrite(s);
262      }
# Line 337 | Line 343 | public class StampedLockTest extends JSR
343       */
344      public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
345          final StampedLock lock = new StampedLock();
346 <        long s = lock.writeLock();
346 >        long stamp = lock.writeLock();
347  
348          Action[] interruptibleLockBlockingActions = {
349              () -> lock.writeLockInterruptibly(),
# Line 352 | Line 358 | public class StampedLockTest extends JSR
358          shuffle(interruptibleLockBlockingActions);
359  
360          assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
361 +
362 +        releaseWriteLock(lock, stamp);
363      }
364  
365      /**
# Line 359 | Line 367 | public class StampedLockTest extends JSR
367       */
368      public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
369          final StampedLock lock = new StampedLock();
370 <        long s = lock.readLock();
370 >        long stamp = lock.readLock();
371  
372          Action[] interruptibleLockBlockingActions = {
373              () -> lock.writeLockInterruptibly(),
# Line 370 | Line 378 | public class StampedLockTest extends JSR
378          shuffle(interruptibleLockBlockingActions);
379  
380          assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
381 +
382 +        releaseReadLock(lock, stamp);
383      }
384  
385      /**
# Line 476 | Line 486 | public class StampedLockTest extends JSR
486      }
487  
488      /**
489 <     * A writelock succeeds only after a reading thread unlocks
489 >     * writeLock() succeeds only after a reading thread unlocks
490       */
491      public void testWriteAfterReadLock() throws InterruptedException {
492 <        final CountDownLatch running = new CountDownLatch(1);
492 >        final CountDownLatch aboutToLock = new CountDownLatch(1);
493          final StampedLock lock = new StampedLock();
494          long rs = lock.readLock();
495          Thread t = newStartedThread(new CheckedRunnable() {
496              public void realRun() {
497 <                running.countDown();
497 >                aboutToLock.countDown();
498                  long s = lock.writeLock();
499 +                assertTrue(lock.isWriteLocked());
500 +                assertFalse(lock.isReadLocked());
501                  lock.unlockWrite(s);
502              }});
503  
504 <        running.await();
505 <        waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS);
504 >        await(aboutToLock);
505 >        assertThreadBlocks(t, Thread.State.WAITING);
506          assertFalse(lock.isWriteLocked());
507 +        assertTrue(lock.isReadLocked());
508          lock.unlockRead(rs);
509          awaitTermination(t);
510 <        assertFalse(lock.isWriteLocked());
510 >        assertUnlocked(lock);
511      }
512  
513      /**
514 <     * A writelock succeeds only after reading threads unlock
514 >     * writeLock() succeeds only after reading threads unlock
515       */
516      public void testWriteAfterMultipleReadLocks() {
517          final StampedLock lock = new StampedLock();
# Line 521 | Line 534 | public class StampedLockTest extends JSR
534          assertFalse(lock.isWriteLocked());
535          lock.unlockRead(s);
536          awaitTermination(t2);
537 <        assertFalse(lock.isWriteLocked());
537 >        assertUnlocked(lock);
538      }
539  
540      /**
541 <     * Readlocks succeed only after a writing thread unlocks
541 >     * readLock() succeed only after a writing thread unlocks
542       */
543      public void testReadAfterWriteLock() {
544          final StampedLock lock = new StampedLock();
545          final CountDownLatch threadsStarted = new CountDownLatch(2);
546          final long s = lock.writeLock();
547 <        Thread t1 = newStartedThread(new CheckedRunnable() {
535 <            public void realRun() {
536 <                threadsStarted.countDown();
537 <                long rs = lock.readLock();
538 <                lock.unlockRead(rs);
539 <            }});
540 <        Thread t2 = newStartedThread(new CheckedRunnable() {
547 >        final Runnable acquireReleaseReadLock = new CheckedRunnable() {
548              public void realRun() {
549                  threadsStarted.countDown();
550                  long rs = lock.readLock();
551 +                assertTrue(lock.isReadLocked());
552 +                assertFalse(lock.isWriteLocked());
553                  lock.unlockRead(rs);
554 <            }});
554 >            }};
555 >        Thread t1 = newStartedThread(acquireReleaseReadLock);
556 >        Thread t2 = newStartedThread(acquireReleaseReadLock);
557  
558          await(threadsStarted);
559 <        waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS);
560 <        waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS);
559 >        assertThreadBlocks(t1, Thread.State.WAITING);
560 >        assertThreadBlocks(t2, Thread.State.WAITING);
561 >        assertTrue(lock.isWriteLocked());
562 >        assertFalse(lock.isReadLocked());
563          releaseWriteLock(lock, s);
564          awaitTermination(t1);
565          awaitTermination(t2);
566 +        assertUnlocked(lock);
567      }
568  
569      /**
# Line 577 | Line 591 | public class StampedLockTest extends JSR
591          long s = lock.readLock();
592          Thread t = newStartedThread(new CheckedRunnable() {
593              public void realRun() {
594 <                threadAssertEquals(0L, lock.tryWriteLock());
594 >                assertEquals(0L, lock.tryWriteLock());
595              }});
596  
597          awaitTermination(t);
# Line 735 | Line 749 | public class StampedLockTest extends JSR
749       */
750      public void testValidateOptimisticWriteLocked2()
751              throws InterruptedException {
752 <        final CountDownLatch running = new CountDownLatch(1);
752 >        final CountDownLatch locked = new CountDownLatch(1);
753          final StampedLock lock = new StampedLock();
754          final long p = assertValid(lock, lock.tryOptimisticRead());
755  
756          Thread t = newStartedThread(new CheckedInterruptedRunnable() {
757              public void realRun() throws InterruptedException {
758                  lock.writeLockInterruptibly();
759 <                running.countDown();
759 >                locked.countDown();
760                  lock.writeLockInterruptibly();
761              }});
762  
763 <        running.await();
763 >        await(locked);
764          assertFalse(lock.validate(p));
765          assertEquals(0L, lock.tryOptimisticRead());
766 +        assertThreadBlocks(t, Thread.State.WAITING);
767          t.interrupt();
768          awaitTermination(t);
769 +        assertTrue(lock.isWriteLocked());
770      }
771  
772      /**
# Line 970 | Line 986 | public class StampedLockTest extends JSR
986       * IllegalMonitorStateException
987       */
988      public void testCannotUnlockOptimisticReadStamps() {
989 <        Runnable[] actions = {
990 <            () -> {
991 <                StampedLock sl = new StampedLock();
992 <                long stamp = assertValid(sl, sl.tryOptimisticRead());
993 <                sl.unlockRead(stamp);
994 <            },
995 <            () -> {
996 <                StampedLock sl = new StampedLock();
997 <                long stamp = sl.tryOptimisticRead();
998 <                sl.unlock(stamp);
999 <            },
1000 <
985 <            () -> {
986 <                StampedLock sl = new StampedLock();
987 <                long stamp = sl.tryOptimisticRead();
988 <                sl.writeLock();
989 <                sl.unlock(stamp);
990 <            },
991 <            () -> {
992 <                StampedLock sl = new StampedLock();
993 <                sl.readLock();
994 <                long stamp = assertValid(sl, sl.tryOptimisticRead());
995 <                sl.unlockRead(stamp);
996 <            },
997 <            () -> {
998 <                StampedLock sl = new StampedLock();
999 <                sl.readLock();
1000 <                long stamp = assertValid(sl, sl.tryOptimisticRead());
1001 <                sl.unlock(stamp);
1002 <            },
989 >        {
990 >            StampedLock sl = new StampedLock();
991 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
992 >            assertThrows(IllegalMonitorStateException.class,
993 >                () -> sl.unlockRead(stamp));
994 >        }
995 >        {
996 >            StampedLock sl = new StampedLock();
997 >            long stamp = sl.tryOptimisticRead();
998 >            assertThrows(IllegalMonitorStateException.class,
999 >                () -> sl.unlock(stamp));
1000 >        }
1001  
1002 <            () -> {
1003 <                StampedLock sl = new StampedLock();
1004 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1005 <                assertValid(sl, stamp);
1006 <                sl.writeLock();
1007 <                sl.unlockWrite(stamp);
1008 <            },
1009 <            () -> {
1010 <                StampedLock sl = new StampedLock();
1011 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1012 <                sl.writeLock();
1013 <                sl.unlock(stamp);
1014 <            },
1015 <            () -> {
1016 <                StampedLock sl = new StampedLock();
1017 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1018 <                sl.readLock();
1019 <                sl.unlockRead(stamp);
1020 <            },
1021 <            () -> {
1022 <                StampedLock sl = new StampedLock();
1025 <                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1026 <                sl.readLock();
1027 <                sl.unlock(stamp);
1028 <            },
1002 >        {
1003 >            StampedLock sl = new StampedLock();
1004 >            long stamp = sl.tryOptimisticRead();
1005 >            sl.writeLock();
1006 >            assertThrows(IllegalMonitorStateException.class,
1007 >                () -> sl.unlock(stamp));
1008 >        }
1009 >        {
1010 >            StampedLock sl = new StampedLock();
1011 >            sl.readLock();
1012 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
1013 >            assertThrows(IllegalMonitorStateException.class,
1014 >                () -> sl.unlockRead(stamp));
1015 >        }
1016 >        {
1017 >            StampedLock sl = new StampedLock();
1018 >            sl.readLock();
1019 >            long stamp = assertValid(sl, sl.tryOptimisticRead());
1020 >            assertThrows(IllegalMonitorStateException.class,
1021 >                () -> sl.unlock(stamp));
1022 >        }
1023  
1024 <            () -> {
1025 <                StampedLock sl = new StampedLock();
1026 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1027 <                assertValid(sl, stamp);
1028 <                sl.writeLock();
1029 <                sl.unlockWrite(stamp);
1030 <            },
1031 <            () -> {
1032 <                StampedLock sl = new StampedLock();
1033 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1034 <                sl.writeLock();
1035 <                sl.unlock(stamp);
1036 <            },
1037 <            () -> {
1038 <                StampedLock sl = new StampedLock();
1039 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1040 <                sl.readLock();
1041 <                sl.unlockRead(stamp);
1042 <            },
1043 <            () -> {
1044 <                StampedLock sl = new StampedLock();
1045 <                sl.readLock();
1046 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1047 <                assertValid(sl, stamp);
1048 <                sl.readLock();
1049 <                sl.unlockRead(stamp);
1050 <            },
1051 <            () -> {
1052 <                StampedLock sl = new StampedLock();
1059 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1060 <                sl.readLock();
1061 <                sl.unlock(stamp);
1062 <            },
1063 <            () -> {
1064 <                StampedLock sl = new StampedLock();
1065 <                sl.readLock();
1066 <                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1067 <                sl.readLock();
1068 <                sl.unlock(stamp);
1069 <            },
1070 <        };
1024 >        {
1025 >            StampedLock sl = new StampedLock();
1026 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1027 >            assertValid(sl, stamp);
1028 >            sl.writeLock();
1029 >            assertThrows(IllegalMonitorStateException.class,
1030 >                () -> sl.unlockWrite(stamp));
1031 >        }
1032 >        {
1033 >            StampedLock sl = new StampedLock();
1034 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1035 >            sl.writeLock();
1036 >            assertThrows(IllegalMonitorStateException.class,
1037 >                () -> sl.unlock(stamp));
1038 >        }
1039 >        {
1040 >            StampedLock sl = new StampedLock();
1041 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1042 >            sl.readLock();
1043 >            assertThrows(IllegalMonitorStateException.class,
1044 >                () -> sl.unlockRead(stamp));
1045 >        }
1046 >        {
1047 >            StampedLock sl = new StampedLock();
1048 >            long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1049 >            sl.readLock();
1050 >            assertThrows(IllegalMonitorStateException.class,
1051 >                () -> sl.unlock(stamp));
1052 >        }
1053  
1054 <        assertThrows(IllegalMonitorStateException.class, actions);
1054 >        {
1055 >            StampedLock sl = new StampedLock();
1056 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1057 >            assertValid(sl, stamp);
1058 >            sl.writeLock();
1059 >            assertThrows(IllegalMonitorStateException.class,
1060 >                () -> sl.unlockWrite(stamp));
1061 >            }
1062 >        {
1063 >            StampedLock sl = new StampedLock();
1064 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1065 >            sl.writeLock();
1066 >            assertThrows(IllegalMonitorStateException.class,
1067 >                () -> sl.unlock(stamp));
1068 >        }
1069 >        {
1070 >            StampedLock sl = new StampedLock();
1071 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1072 >            sl.readLock();
1073 >            assertThrows(IllegalMonitorStateException.class,
1074 >                () -> sl.unlockRead(stamp));
1075 >        }
1076 >        {
1077 >            StampedLock sl = new StampedLock();
1078 >            sl.readLock();
1079 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1080 >            assertValid(sl, stamp);
1081 >            sl.readLock();
1082 >            assertThrows(IllegalMonitorStateException.class,
1083 >                () -> sl.unlockRead(stamp));
1084 >        }
1085 >        {
1086 >            StampedLock sl = new StampedLock();
1087 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1088 >            sl.readLock();
1089 >            assertThrows(IllegalMonitorStateException.class,
1090 >                () -> sl.unlock(stamp));
1091 >        }
1092 >        {
1093 >            StampedLock sl = new StampedLock();
1094 >            sl.readLock();
1095 >            long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1096 >            sl.readLock();
1097 >            assertThrows(IllegalMonitorStateException.class,
1098 >                () -> sl.unlock(stamp));
1099 >        }
1100      }
1101  
1102      static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
# Line 1173 | Line 1200 | public class StampedLockTest extends JSR
1200          }
1201          assertUnlocked(lock);
1202      }
1203 +
1204 +    /**
1205 +     * Stamped locks are not reentrant.
1206 +     */
1207 +    public void testNonReentrant() throws InterruptedException {
1208 +        final StampedLock lock = new StampedLock();
1209 +        long stamp;
1210 +
1211 +        stamp = lock.writeLock();
1212 +        assertValid(lock, stamp);
1213 +        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1214 +        assertEquals(0L, lock.tryReadLock(0L, DAYS));
1215 +        assertValid(lock, stamp);
1216 +        lock.unlockWrite(stamp);
1217 +
1218 +        stamp = lock.tryWriteLock(1L, DAYS);
1219 +        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1220 +        assertValid(lock, stamp);
1221 +        lock.unlockWrite(stamp);
1222 +
1223 +        stamp = lock.readLock();
1224 +        assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1225 +        assertValid(lock, stamp);
1226 +        lock.unlockRead(stamp);
1227 +    }
1228 +
1229 +    /**
1230 +     * """StampedLocks have no notion of ownership. Locks acquired in
1231 +     * one thread can be released or converted in another."""
1232 +     */
1233 +    public void testNoOwnership() throws Throwable {
1234 +        ArrayList<Future<?>> futures = new ArrayList<>();
1235 +        for (Function<StampedLock, Long> writeLocker : writeLockers())
1236 +        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1237 +            StampedLock lock = new StampedLock();
1238 +            long stamp = writeLocker.apply(lock);
1239 +            futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1240 +                public void realRun() {
1241 +                    writeUnlocker.accept(lock, stamp);
1242 +                    assertUnlocked(lock);
1243 +                    assertFalse(lock.validate(stamp));
1244 +                }}));
1245 +        }
1246 +        for (Future<?> future : futures)
1247 +            assertNull(future.get());
1248 +    }
1249 +
1250 +    /** Tries out sample usage code from StampedLock javadoc. */
1251 +    public void testSampleUsage() throws Throwable {
1252 +        class Point {
1253 +            private double x, y;
1254 +            private final StampedLock sl = new StampedLock();
1255 +
1256 +            void move(double deltaX, double deltaY) { // an exclusively locked method
1257 +                long stamp = sl.writeLock();
1258 +                try {
1259 +                    x += deltaX;
1260 +                    y += deltaY;
1261 +                } finally {
1262 +                    sl.unlockWrite(stamp);
1263 +                }
1264 +            }
1265 +
1266 +            double distanceFromOrigin() { // A read-only method
1267 +                double currentX, currentY;
1268 +                long stamp = sl.tryOptimisticRead();
1269 +                do {
1270 +                    if (stamp == 0L)
1271 +                        stamp = sl.readLock();
1272 +                    try {
1273 +                        // possibly racy reads
1274 +                        currentX = x;
1275 +                        currentY = y;
1276 +                    } finally {
1277 +                        stamp = sl.tryConvertToOptimisticRead(stamp);
1278 +                    }
1279 +                } while (stamp == 0);
1280 +                return Math.hypot(currentX, currentY);
1281 +            }
1282 +
1283 +            double distanceFromOrigin2() {
1284 +                long stamp = sl.tryOptimisticRead();
1285 +                try {
1286 +                    retryHoldingLock:
1287 +                    for (;; stamp = sl.readLock()) {
1288 +                        if (stamp == 0L)
1289 +                            continue retryHoldingLock;
1290 +                        // possibly racy reads
1291 +                        double currentX = x;
1292 +                        double currentY = y;
1293 +                        if (!sl.validate(stamp))
1294 +                            continue retryHoldingLock;
1295 +                        return Math.hypot(currentX, currentY);
1296 +                    }
1297 +                } finally {
1298 +                    if (StampedLock.isReadLockStamp(stamp))
1299 +                        sl.unlockRead(stamp);
1300 +                }
1301 +            }
1302 +
1303 +            void moveIfAtOrigin(double newX, double newY) {
1304 +                long stamp = sl.readLock();
1305 +                try {
1306 +                    while (x == 0.0 && y == 0.0) {
1307 +                        long ws = sl.tryConvertToWriteLock(stamp);
1308 +                        if (ws != 0L) {
1309 +                            stamp = ws;
1310 +                            x = newX;
1311 +                            y = newY;
1312 +                            return;
1313 +                        }
1314 +                        else {
1315 +                            sl.unlockRead(stamp);
1316 +                            stamp = sl.writeLock();
1317 +                        }
1318 +                    }
1319 +                } finally {
1320 +                    sl.unlock(stamp);
1321 +                }
1322 +            }
1323 +        }
1324 +
1325 +        Point p = new Point();
1326 +        p.move(3.0, 4.0);
1327 +        assertEquals(5.0, p.distanceFromOrigin());
1328 +        p.moveIfAtOrigin(5.0, 12.0);
1329 +        assertEquals(5.0, p.distanceFromOrigin2());
1330 +    }
1331 +
1332 +    /**
1333 +     * Stamp inspection methods work as expected, and do not inspect
1334 +     * the state of the lock itself.
1335 +     */
1336 +    public void testStampStateInspectionMethods() {
1337 +        StampedLock lock = new StampedLock();
1338 +
1339 +        assertFalse(isWriteLockStamp(0L));
1340 +        assertFalse(isReadLockStamp(0L));
1341 +        assertFalse(isLockStamp(0L));
1342 +        assertFalse(isOptimisticReadStamp(0L));
1343 +
1344 +        {
1345 +            long stamp = lock.writeLock();
1346 +            for (int i = 0; i < 2; i++) {
1347 +                assertTrue(isWriteLockStamp(stamp));
1348 +                assertFalse(isReadLockStamp(stamp));
1349 +                assertTrue(isLockStamp(stamp));
1350 +                assertFalse(isOptimisticReadStamp(stamp));
1351 +                if (i == 0)
1352 +                    lock.unlockWrite(stamp);
1353 +            }
1354 +        }
1355 +
1356 +        {
1357 +            long stamp = lock.readLock();
1358 +            for (int i = 0; i < 2; i++) {
1359 +                assertFalse(isWriteLockStamp(stamp));
1360 +                assertTrue(isReadLockStamp(stamp));
1361 +                assertTrue(isLockStamp(stamp));
1362 +                assertFalse(isOptimisticReadStamp(stamp));
1363 +                if (i == 0)
1364 +                    lock.unlockRead(stamp);
1365 +            }
1366 +        }
1367 +
1368 +        {
1369 +            long optimisticStamp = lock.tryOptimisticRead();
1370 +            long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1371 +            long writeStamp = lock.tryConvertToWriteLock(readStamp);
1372 +            for (int i = 0; i < 2; i++) {
1373 +                assertFalse(isWriteLockStamp(optimisticStamp));
1374 +                assertFalse(isReadLockStamp(optimisticStamp));
1375 +                assertFalse(isLockStamp(optimisticStamp));
1376 +                assertTrue(isOptimisticReadStamp(optimisticStamp));
1377 +
1378 +                assertFalse(isWriteLockStamp(readStamp));
1379 +                assertTrue(isReadLockStamp(readStamp));
1380 +                assertTrue(isLockStamp(readStamp));
1381 +                assertFalse(isOptimisticReadStamp(readStamp));
1382 +
1383 +                assertTrue(isWriteLockStamp(writeStamp));
1384 +                assertFalse(isReadLockStamp(writeStamp));
1385 +                assertTrue(isLockStamp(writeStamp));
1386 +                assertFalse(isOptimisticReadStamp(writeStamp));
1387 +                if (i == 0)
1388 +                    lock.unlockWrite(writeStamp);
1389 +            }
1390 +        }
1391 +    }
1392 +
1393 +    /**
1394 +     * Multiple threads repeatedly contend for the same lock.
1395 +     */
1396 +    public void testConcurrentAccess() throws Exception {
1397 +        final StampedLock sl = new StampedLock();
1398 +        final Lock wl = sl.asWriteLock();
1399 +        final Lock rl = sl.asReadLock();
1400 +        final long testDurationMillis = expensiveTests ? 1000 : 2;
1401 +        final int nTasks = ThreadLocalRandom.current().nextInt(1, 10);
1402 +        final AtomicBoolean done = new AtomicBoolean(false);
1403 +        final List<CompletableFuture> futures = new ArrayList<>();
1404 +        final List<Callable<Long>> stampedWriteLockers = List.of(
1405 +            () -> sl.writeLock(),
1406 +            () -> writeLockInterruptiblyUninterrupted(sl),
1407 +            () -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1408 +            () -> {
1409 +                long stamp;
1410 +                do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); }
1411 +                while (stamp == 0L);
1412 +                return stamp;
1413 +            },
1414 +            () -> {
1415 +              long stamp;
1416 +              do { stamp = sl.tryWriteLock(); } while (stamp == 0L);
1417 +              return stamp;
1418 +            },
1419 +            () -> {
1420 +              long stamp;
1421 +              do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L);
1422 +              return stamp;
1423 +            });
1424 +        final List<Callable<Long>> stampedReadLockers = List.of(
1425 +            () -> sl.readLock(),
1426 +            () -> readLockInterruptiblyUninterrupted(sl),
1427 +            () -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1428 +            () -> {
1429 +                long stamp;
1430 +                do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); }
1431 +                while (stamp == 0L);
1432 +                return stamp;
1433 +            },
1434 +            () -> {
1435 +              long stamp;
1436 +              do { stamp = sl.tryReadLock(); } while (stamp == 0L);
1437 +              return stamp;
1438 +            },
1439 +            () -> {
1440 +              long stamp;
1441 +              do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L);
1442 +              return stamp;
1443 +            });
1444 +        final List<Consumer<Long>> stampedWriteUnlockers = List.of(
1445 +            stamp -> sl.unlockWrite(stamp),
1446 +            stamp -> sl.unlock(stamp),
1447 +            stamp -> assertTrue(sl.tryUnlockWrite()),
1448 +            stamp -> wl.unlock(),
1449 +            stamp -> sl.tryConvertToOptimisticRead(stamp));
1450 +        final List<Consumer<Long>> stampedReadUnlockers = List.of(
1451 +            stamp -> sl.unlockRead(stamp),
1452 +            stamp -> sl.unlock(stamp),
1453 +            stamp -> assertTrue(sl.tryUnlockRead()),
1454 +            stamp -> rl.unlock(),
1455 +            stamp -> sl.tryConvertToOptimisticRead(stamp));
1456 +        final Action writer = () -> {
1457 +            // repeatedly acquires write lock
1458 +            var locker = chooseRandomly(stampedWriteLockers);
1459 +            var unlocker = chooseRandomly(stampedWriteUnlockers);
1460 +            while (!done.getAcquire()) {
1461 +                long stamp = locker.call();
1462 +                try {
1463 +                    assertTrue(isWriteLockStamp(stamp));
1464 +                    assertTrue(sl.isWriteLocked());
1465 +                    assertFalse(isReadLockStamp(stamp));
1466 +                    assertFalse(sl.isReadLocked());
1467 +                    assertEquals(0, sl.getReadLockCount());
1468 +                    assertTrue(sl.validate(stamp));
1469 +                } finally {
1470 +                    unlocker.accept(stamp);
1471 +                }
1472 +            }
1473 +        };
1474 +        final Action reader = () -> {
1475 +            // repeatedly acquires read lock
1476 +            var locker = chooseRandomly(stampedReadLockers);
1477 +            var unlocker = chooseRandomly(stampedReadUnlockers);
1478 +            while (!done.getAcquire()) {
1479 +                long stamp = locker.call();
1480 +                try {
1481 +                    assertFalse(isWriteLockStamp(stamp));
1482 +                    assertFalse(sl.isWriteLocked());
1483 +                    assertTrue(isReadLockStamp(stamp));
1484 +                    assertTrue(sl.isReadLocked());
1485 +                    assertTrue(sl.getReadLockCount() > 0);
1486 +                    assertTrue(sl.validate(stamp));
1487 +                } finally {
1488 +                    unlocker.accept(stamp);
1489 +                }
1490 +            }
1491 +        };
1492 +        for (int i = nTasks; i--> 0; ) {
1493 +            Action task = chooseRandomly(writer, reader);
1494 +            futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
1495 +        }
1496 +        Thread.sleep(testDurationMillis);
1497 +        done.setRelease(true);
1498 +        for (var future : futures)
1499 +            checkTimedGet(future, null);
1500 +    }
1501 +
1502   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines