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; |
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 |
|
/** |
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 |
|
} |
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(), |
358 |
|
shuffle(interruptibleLockBlockingActions); |
359 |
|
|
360 |
|
assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions); |
361 |
+ |
|
362 |
+ |
releaseWriteLock(lock, stamp); |
363 |
|
} |
364 |
|
|
365 |
|
/** |
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(), |
378 |
|
shuffle(interruptibleLockBlockingActions); |
379 |
|
|
380 |
|
assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions); |
381 |
+ |
|
382 |
+ |
releaseReadLock(lock, stamp); |
383 |
|
} |
384 |
|
|
385 |
|
/** |
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(); |
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 |
|
/** |
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); |
703 |
|
lock.unlockWrite(s); |
704 |
|
s = lock.readLock(); |
705 |
|
assertTrue(lock.toString().contains("Read-locks")); |
706 |
+ |
releaseReadLock(lock, s); |
707 |
|
} |
708 |
|
|
709 |
|
/** |
750 |
|
*/ |
751 |
|
public void testValidateOptimisticWriteLocked2() |
752 |
|
throws InterruptedException { |
753 |
< |
final CountDownLatch running = new CountDownLatch(1); |
753 |
> |
final CountDownLatch locked = new CountDownLatch(1); |
754 |
|
final StampedLock lock = new StampedLock(); |
755 |
|
final long p = assertValid(lock, lock.tryOptimisticRead()); |
756 |
|
|
757 |
|
Thread t = newStartedThread(new CheckedInterruptedRunnable() { |
758 |
|
public void realRun() throws InterruptedException { |
759 |
|
lock.writeLockInterruptibly(); |
760 |
< |
running.countDown(); |
760 |
> |
locked.countDown(); |
761 |
|
lock.writeLockInterruptibly(); |
762 |
|
}}); |
763 |
|
|
764 |
< |
running.await(); |
764 |
> |
await(locked); |
765 |
|
assertFalse(lock.validate(p)); |
766 |
|
assertEquals(0L, lock.tryOptimisticRead()); |
767 |
+ |
assertThreadBlocks(t, Thread.State.WAITING); |
768 |
|
t.interrupt(); |
769 |
|
awaitTermination(t); |
770 |
+ |
assertTrue(lock.isWriteLocked()); |
771 |
|
} |
772 |
|
|
773 |
|
/** |
987 |
|
* IllegalMonitorStateException |
988 |
|
*/ |
989 |
|
public void testCannotUnlockOptimisticReadStamps() { |
990 |
< |
Runnable[] actions = { |
991 |
< |
() -> { |
992 |
< |
StampedLock sl = new StampedLock(); |
993 |
< |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
994 |
< |
sl.unlockRead(stamp); |
995 |
< |
}, |
996 |
< |
() -> { |
997 |
< |
StampedLock sl = new StampedLock(); |
998 |
< |
long stamp = sl.tryOptimisticRead(); |
999 |
< |
sl.unlock(stamp); |
1000 |
< |
}, |
1001 |
< |
|
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 |
< |
}, |
990 |
> |
{ |
991 |
> |
StampedLock sl = new StampedLock(); |
992 |
> |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
993 |
> |
assertThrows(IllegalMonitorStateException.class, |
994 |
> |
() -> sl.unlockRead(stamp)); |
995 |
> |
} |
996 |
> |
{ |
997 |
> |
StampedLock sl = new StampedLock(); |
998 |
> |
long stamp = sl.tryOptimisticRead(); |
999 |
> |
assertThrows(IllegalMonitorStateException.class, |
1000 |
> |
() -> sl.unlock(stamp)); |
1001 |
> |
} |
1002 |
|
|
1003 |
< |
() -> { |
1004 |
< |
StampedLock sl = new StampedLock(); |
1005 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1006 |
< |
assertValid(sl, stamp); |
1007 |
< |
sl.writeLock(); |
1008 |
< |
sl.unlockWrite(stamp); |
1009 |
< |
}, |
1010 |
< |
() -> { |
1011 |
< |
StampedLock sl = new StampedLock(); |
1012 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1013 |
< |
sl.writeLock(); |
1014 |
< |
sl.unlock(stamp); |
1015 |
< |
}, |
1016 |
< |
() -> { |
1017 |
< |
StampedLock sl = new StampedLock(); |
1018 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1019 |
< |
sl.readLock(); |
1020 |
< |
sl.unlockRead(stamp); |
1021 |
< |
}, |
1022 |
< |
() -> { |
1023 |
< |
StampedLock sl = new StampedLock(); |
1025 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1026 |
< |
sl.readLock(); |
1027 |
< |
sl.unlock(stamp); |
1028 |
< |
}, |
1003 |
> |
{ |
1004 |
> |
StampedLock sl = new StampedLock(); |
1005 |
> |
long stamp = sl.tryOptimisticRead(); |
1006 |
> |
sl.writeLock(); |
1007 |
> |
assertThrows(IllegalMonitorStateException.class, |
1008 |
> |
() -> sl.unlock(stamp)); |
1009 |
> |
} |
1010 |
> |
{ |
1011 |
> |
StampedLock sl = new StampedLock(); |
1012 |
> |
sl.readLock(); |
1013 |
> |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
1014 |
> |
assertThrows(IllegalMonitorStateException.class, |
1015 |
> |
() -> sl.unlockRead(stamp)); |
1016 |
> |
} |
1017 |
> |
{ |
1018 |
> |
StampedLock sl = new StampedLock(); |
1019 |
> |
sl.readLock(); |
1020 |
> |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
1021 |
> |
assertThrows(IllegalMonitorStateException.class, |
1022 |
> |
() -> sl.unlock(stamp)); |
1023 |
> |
} |
1024 |
|
|
1025 |
< |
() -> { |
1026 |
< |
StampedLock sl = new StampedLock(); |
1027 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1028 |
< |
assertValid(sl, stamp); |
1029 |
< |
sl.writeLock(); |
1030 |
< |
sl.unlockWrite(stamp); |
1031 |
< |
}, |
1032 |
< |
() -> { |
1033 |
< |
StampedLock sl = new StampedLock(); |
1034 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1035 |
< |
sl.writeLock(); |
1036 |
< |
sl.unlock(stamp); |
1037 |
< |
}, |
1038 |
< |
() -> { |
1039 |
< |
StampedLock sl = new StampedLock(); |
1040 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1041 |
< |
sl.readLock(); |
1042 |
< |
sl.unlockRead(stamp); |
1043 |
< |
}, |
1044 |
< |
() -> { |
1045 |
< |
StampedLock sl = new StampedLock(); |
1046 |
< |
sl.readLock(); |
1047 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1048 |
< |
assertValid(sl, stamp); |
1049 |
< |
sl.readLock(); |
1050 |
< |
sl.unlockRead(stamp); |
1051 |
< |
}, |
1052 |
< |
() -> { |
1053 |
< |
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 |
< |
}; |
1025 |
> |
{ |
1026 |
> |
StampedLock sl = new StampedLock(); |
1027 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1028 |
> |
assertValid(sl, stamp); |
1029 |
> |
sl.writeLock(); |
1030 |
> |
assertThrows(IllegalMonitorStateException.class, |
1031 |
> |
() -> sl.unlockWrite(stamp)); |
1032 |
> |
} |
1033 |
> |
{ |
1034 |
> |
StampedLock sl = new StampedLock(); |
1035 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1036 |
> |
sl.writeLock(); |
1037 |
> |
assertThrows(IllegalMonitorStateException.class, |
1038 |
> |
() -> sl.unlock(stamp)); |
1039 |
> |
} |
1040 |
> |
{ |
1041 |
> |
StampedLock sl = new StampedLock(); |
1042 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1043 |
> |
sl.readLock(); |
1044 |
> |
assertThrows(IllegalMonitorStateException.class, |
1045 |
> |
() -> sl.unlockRead(stamp)); |
1046 |
> |
} |
1047 |
> |
{ |
1048 |
> |
StampedLock sl = new StampedLock(); |
1049 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1050 |
> |
sl.readLock(); |
1051 |
> |
assertThrows(IllegalMonitorStateException.class, |
1052 |
> |
() -> sl.unlock(stamp)); |
1053 |
> |
} |
1054 |
|
|
1055 |
< |
assertThrows(IllegalMonitorStateException.class, actions); |
1055 |
> |
{ |
1056 |
> |
StampedLock sl = new StampedLock(); |
1057 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1058 |
> |
assertValid(sl, stamp); |
1059 |
> |
sl.writeLock(); |
1060 |
> |
assertThrows(IllegalMonitorStateException.class, |
1061 |
> |
() -> sl.unlockWrite(stamp)); |
1062 |
> |
} |
1063 |
> |
{ |
1064 |
> |
StampedLock sl = new StampedLock(); |
1065 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1066 |
> |
sl.writeLock(); |
1067 |
> |
assertThrows(IllegalMonitorStateException.class, |
1068 |
> |
() -> sl.unlock(stamp)); |
1069 |
> |
} |
1070 |
> |
{ |
1071 |
> |
StampedLock sl = new StampedLock(); |
1072 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1073 |
> |
sl.readLock(); |
1074 |
> |
assertThrows(IllegalMonitorStateException.class, |
1075 |
> |
() -> sl.unlockRead(stamp)); |
1076 |
> |
} |
1077 |
> |
{ |
1078 |
> |
StampedLock sl = new StampedLock(); |
1079 |
> |
sl.readLock(); |
1080 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1081 |
> |
assertValid(sl, stamp); |
1082 |
> |
sl.readLock(); |
1083 |
> |
assertThrows(IllegalMonitorStateException.class, |
1084 |
> |
() -> sl.unlockRead(stamp)); |
1085 |
> |
} |
1086 |
> |
{ |
1087 |
> |
StampedLock sl = new StampedLock(); |
1088 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1089 |
> |
sl.readLock(); |
1090 |
> |
assertThrows(IllegalMonitorStateException.class, |
1091 |
> |
() -> sl.unlock(stamp)); |
1092 |
> |
} |
1093 |
> |
{ |
1094 |
> |
StampedLock sl = new StampedLock(); |
1095 |
> |
sl.readLock(); |
1096 |
> |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1097 |
> |
sl.readLock(); |
1098 |
> |
assertThrows(IllegalMonitorStateException.class, |
1099 |
> |
() -> sl.unlock(stamp)); |
1100 |
> |
} |
1101 |
|
} |
1102 |
|
|
1103 |
|
static long writeLockInterruptiblyUninterrupted(StampedLock sl) { |
1201 |
|
} |
1202 |
|
assertUnlocked(lock); |
1203 |
|
} |
1204 |
+ |
|
1205 |
+ |
/** |
1206 |
+ |
* Stamped locks are not reentrant. |
1207 |
+ |
*/ |
1208 |
+ |
public void testNonReentrant() throws InterruptedException { |
1209 |
+ |
final StampedLock lock = new StampedLock(); |
1210 |
+ |
long stamp; |
1211 |
+ |
|
1212 |
+ |
stamp = lock.writeLock(); |
1213 |
+ |
assertValid(lock, stamp); |
1214 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1215 |
+ |
assertEquals(0L, lock.tryReadLock(0L, DAYS)); |
1216 |
+ |
assertValid(lock, stamp); |
1217 |
+ |
lock.unlockWrite(stamp); |
1218 |
+ |
|
1219 |
+ |
stamp = lock.tryWriteLock(1L, DAYS); |
1220 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1221 |
+ |
assertValid(lock, stamp); |
1222 |
+ |
lock.unlockWrite(stamp); |
1223 |
+ |
|
1224 |
+ |
stamp = lock.readLock(); |
1225 |
+ |
assertEquals(0L, lock.tryWriteLock(0L, DAYS)); |
1226 |
+ |
assertValid(lock, stamp); |
1227 |
+ |
lock.unlockRead(stamp); |
1228 |
+ |
} |
1229 |
+ |
|
1230 |
+ |
/** |
1231 |
+ |
* """StampedLocks have no notion of ownership. Locks acquired in |
1232 |
+ |
* one thread can be released or converted in another.""" |
1233 |
+ |
*/ |
1234 |
+ |
public void testNoOwnership() throws Throwable { |
1235 |
+ |
ArrayList<Future<?>> futures = new ArrayList<>(); |
1236 |
+ |
for (Function<StampedLock, Long> writeLocker : writeLockers()) |
1237 |
+ |
for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { |
1238 |
+ |
StampedLock lock = new StampedLock(); |
1239 |
+ |
long stamp = writeLocker.apply(lock); |
1240 |
+ |
futures.add(cachedThreadPool.submit(new CheckedRunnable() { |
1241 |
+ |
public void realRun() { |
1242 |
+ |
writeUnlocker.accept(lock, stamp); |
1243 |
+ |
assertUnlocked(lock); |
1244 |
+ |
assertFalse(lock.validate(stamp)); |
1245 |
+ |
}})); |
1246 |
+ |
} |
1247 |
+ |
for (Future<?> future : futures) |
1248 |
+ |
assertNull(future.get()); |
1249 |
+ |
} |
1250 |
+ |
|
1251 |
+ |
/** Tries out sample usage code from StampedLock javadoc. */ |
1252 |
+ |
public void testSampleUsage() throws Throwable { |
1253 |
+ |
class Point { |
1254 |
+ |
private double x, y; |
1255 |
+ |
private final StampedLock sl = new StampedLock(); |
1256 |
+ |
|
1257 |
+ |
void move(double deltaX, double deltaY) { // an exclusively locked method |
1258 |
+ |
long stamp = sl.writeLock(); |
1259 |
+ |
try { |
1260 |
+ |
x += deltaX; |
1261 |
+ |
y += deltaY; |
1262 |
+ |
} finally { |
1263 |
+ |
sl.unlockWrite(stamp); |
1264 |
+ |
} |
1265 |
+ |
} |
1266 |
+ |
|
1267 |
+ |
double distanceFromOrigin() { // A read-only method |
1268 |
+ |
double currentX, currentY; |
1269 |
+ |
long stamp = sl.tryOptimisticRead(); |
1270 |
+ |
do { |
1271 |
+ |
if (stamp == 0L) |
1272 |
+ |
stamp = sl.readLock(); |
1273 |
+ |
try { |
1274 |
+ |
// possibly racy reads |
1275 |
+ |
currentX = x; |
1276 |
+ |
currentY = y; |
1277 |
+ |
} finally { |
1278 |
+ |
stamp = sl.tryConvertToOptimisticRead(stamp); |
1279 |
+ |
} |
1280 |
+ |
} while (stamp == 0); |
1281 |
+ |
return Math.hypot(currentX, currentY); |
1282 |
+ |
} |
1283 |
+ |
|
1284 |
+ |
double distanceFromOrigin2() { |
1285 |
+ |
long stamp = sl.tryOptimisticRead(); |
1286 |
+ |
try { |
1287 |
+ |
retryHoldingLock: |
1288 |
+ |
for (;; stamp = sl.readLock()) { |
1289 |
+ |
if (stamp == 0L) |
1290 |
+ |
continue retryHoldingLock; |
1291 |
+ |
// possibly racy reads |
1292 |
+ |
double currentX = x; |
1293 |
+ |
double currentY = y; |
1294 |
+ |
if (!sl.validate(stamp)) |
1295 |
+ |
continue retryHoldingLock; |
1296 |
+ |
return Math.hypot(currentX, currentY); |
1297 |
+ |
} |
1298 |
+ |
} finally { |
1299 |
+ |
if (StampedLock.isReadLockStamp(stamp)) |
1300 |
+ |
sl.unlockRead(stamp); |
1301 |
+ |
} |
1302 |
+ |
} |
1303 |
+ |
|
1304 |
+ |
void moveIfAtOrigin(double newX, double newY) { |
1305 |
+ |
long stamp = sl.readLock(); |
1306 |
+ |
try { |
1307 |
+ |
while (x == 0.0 && y == 0.0) { |
1308 |
+ |
long ws = sl.tryConvertToWriteLock(stamp); |
1309 |
+ |
if (ws != 0L) { |
1310 |
+ |
stamp = ws; |
1311 |
+ |
x = newX; |
1312 |
+ |
y = newY; |
1313 |
+ |
return; |
1314 |
+ |
} |
1315 |
+ |
else { |
1316 |
+ |
sl.unlockRead(stamp); |
1317 |
+ |
stamp = sl.writeLock(); |
1318 |
+ |
} |
1319 |
+ |
} |
1320 |
+ |
} finally { |
1321 |
+ |
sl.unlock(stamp); |
1322 |
+ |
} |
1323 |
+ |
} |
1324 |
+ |
} |
1325 |
+ |
|
1326 |
+ |
Point p = new Point(); |
1327 |
+ |
p.move(3.0, 4.0); |
1328 |
+ |
assertEquals(5.0, p.distanceFromOrigin()); |
1329 |
+ |
p.moveIfAtOrigin(5.0, 12.0); |
1330 |
+ |
assertEquals(5.0, p.distanceFromOrigin2()); |
1331 |
+ |
} |
1332 |
+ |
|
1333 |
+ |
/** |
1334 |
+ |
* Stamp inspection methods work as expected, and do not inspect |
1335 |
+ |
* the state of the lock itself. |
1336 |
+ |
*/ |
1337 |
+ |
public void testStampStateInspectionMethods() { |
1338 |
+ |
StampedLock lock = new StampedLock(); |
1339 |
+ |
|
1340 |
+ |
assertFalse(isWriteLockStamp(0L)); |
1341 |
+ |
assertFalse(isReadLockStamp(0L)); |
1342 |
+ |
assertFalse(isLockStamp(0L)); |
1343 |
+ |
assertFalse(isOptimisticReadStamp(0L)); |
1344 |
+ |
|
1345 |
+ |
{ |
1346 |
+ |
long stamp = lock.writeLock(); |
1347 |
+ |
for (int i = 0; i < 2; i++) { |
1348 |
+ |
assertTrue(isWriteLockStamp(stamp)); |
1349 |
+ |
assertFalse(isReadLockStamp(stamp)); |
1350 |
+ |
assertTrue(isLockStamp(stamp)); |
1351 |
+ |
assertFalse(isOptimisticReadStamp(stamp)); |
1352 |
+ |
if (i == 0) |
1353 |
+ |
lock.unlockWrite(stamp); |
1354 |
+ |
} |
1355 |
+ |
} |
1356 |
+ |
|
1357 |
+ |
{ |
1358 |
+ |
long stamp = lock.readLock(); |
1359 |
+ |
for (int i = 0; i < 2; i++) { |
1360 |
+ |
assertFalse(isWriteLockStamp(stamp)); |
1361 |
+ |
assertTrue(isReadLockStamp(stamp)); |
1362 |
+ |
assertTrue(isLockStamp(stamp)); |
1363 |
+ |
assertFalse(isOptimisticReadStamp(stamp)); |
1364 |
+ |
if (i == 0) |
1365 |
+ |
lock.unlockRead(stamp); |
1366 |
+ |
} |
1367 |
+ |
} |
1368 |
+ |
|
1369 |
+ |
{ |
1370 |
+ |
long optimisticStamp = lock.tryOptimisticRead(); |
1371 |
+ |
long readStamp = lock.tryConvertToReadLock(optimisticStamp); |
1372 |
+ |
long writeStamp = lock.tryConvertToWriteLock(readStamp); |
1373 |
+ |
for (int i = 0; i < 2; i++) { |
1374 |
+ |
assertFalse(isWriteLockStamp(optimisticStamp)); |
1375 |
+ |
assertFalse(isReadLockStamp(optimisticStamp)); |
1376 |
+ |
assertFalse(isLockStamp(optimisticStamp)); |
1377 |
+ |
assertTrue(isOptimisticReadStamp(optimisticStamp)); |
1378 |
+ |
|
1379 |
+ |
assertFalse(isWriteLockStamp(readStamp)); |
1380 |
+ |
assertTrue(isReadLockStamp(readStamp)); |
1381 |
+ |
assertTrue(isLockStamp(readStamp)); |
1382 |
+ |
assertFalse(isOptimisticReadStamp(readStamp)); |
1383 |
+ |
|
1384 |
+ |
assertTrue(isWriteLockStamp(writeStamp)); |
1385 |
+ |
assertFalse(isReadLockStamp(writeStamp)); |
1386 |
+ |
assertTrue(isLockStamp(writeStamp)); |
1387 |
+ |
assertFalse(isOptimisticReadStamp(writeStamp)); |
1388 |
+ |
if (i == 0) |
1389 |
+ |
lock.unlockWrite(writeStamp); |
1390 |
+ |
} |
1391 |
+ |
} |
1392 |
+ |
} |
1393 |
+ |
|
1394 |
+ |
/** |
1395 |
+ |
* Multiple threads repeatedly contend for the same lock. |
1396 |
+ |
*/ |
1397 |
+ |
public void testConcurrentAccess() throws Exception { |
1398 |
+ |
final StampedLock sl = new StampedLock(); |
1399 |
+ |
final Lock wl = sl.asWriteLock(); |
1400 |
+ |
final Lock rl = sl.asReadLock(); |
1401 |
+ |
final long testDurationMillis = expensiveTests ? 1000 : 2; |
1402 |
+ |
final int nTasks = ThreadLocalRandom.current().nextInt(1, 10); |
1403 |
+ |
final AtomicBoolean done = new AtomicBoolean(false); |
1404 |
+ |
final List<CompletableFuture<?>> futures = new ArrayList<>(); |
1405 |
+ |
final List<Callable<Long>> stampedWriteLockers = List.of( |
1406 |
+ |
() -> sl.writeLock(), |
1407 |
+ |
() -> writeLockInterruptiblyUninterrupted(sl), |
1408 |
+ |
() -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), |
1409 |
+ |
() -> { |
1410 |
+ |
long stamp; |
1411 |
+ |
do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); } |
1412 |
+ |
while (stamp == 0L); |
1413 |
+ |
return stamp; |
1414 |
+ |
}, |
1415 |
+ |
() -> { |
1416 |
+ |
long stamp; |
1417 |
+ |
do { stamp = sl.tryWriteLock(); } while (stamp == 0L); |
1418 |
+ |
return stamp; |
1419 |
+ |
}, |
1420 |
+ |
() -> { |
1421 |
+ |
long stamp; |
1422 |
+ |
do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L); |
1423 |
+ |
return stamp; |
1424 |
+ |
}); |
1425 |
+ |
final List<Callable<Long>> stampedReadLockers = List.of( |
1426 |
+ |
() -> sl.readLock(), |
1427 |
+ |
() -> readLockInterruptiblyUninterrupted(sl), |
1428 |
+ |
() -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), |
1429 |
+ |
() -> { |
1430 |
+ |
long stamp; |
1431 |
+ |
do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); } |
1432 |
+ |
while (stamp == 0L); |
1433 |
+ |
return stamp; |
1434 |
+ |
}, |
1435 |
+ |
() -> { |
1436 |
+ |
long stamp; |
1437 |
+ |
do { stamp = sl.tryReadLock(); } while (stamp == 0L); |
1438 |
+ |
return stamp; |
1439 |
+ |
}, |
1440 |
+ |
() -> { |
1441 |
+ |
long stamp; |
1442 |
+ |
do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L); |
1443 |
+ |
return stamp; |
1444 |
+ |
}); |
1445 |
+ |
final List<Consumer<Long>> stampedWriteUnlockers = List.of( |
1446 |
+ |
stamp -> sl.unlockWrite(stamp), |
1447 |
+ |
stamp -> sl.unlock(stamp), |
1448 |
+ |
stamp -> assertTrue(sl.tryUnlockWrite()), |
1449 |
+ |
stamp -> wl.unlock(), |
1450 |
+ |
stamp -> sl.tryConvertToOptimisticRead(stamp)); |
1451 |
+ |
final List<Consumer<Long>> stampedReadUnlockers = List.of( |
1452 |
+ |
stamp -> sl.unlockRead(stamp), |
1453 |
+ |
stamp -> sl.unlock(stamp), |
1454 |
+ |
stamp -> assertTrue(sl.tryUnlockRead()), |
1455 |
+ |
stamp -> rl.unlock(), |
1456 |
+ |
stamp -> sl.tryConvertToOptimisticRead(stamp)); |
1457 |
+ |
final Action writer = () -> { |
1458 |
+ |
// repeatedly acquires write lock |
1459 |
+ |
var locker = chooseRandomly(stampedWriteLockers); |
1460 |
+ |
var unlocker = chooseRandomly(stampedWriteUnlockers); |
1461 |
+ |
while (!done.getAcquire()) { |
1462 |
+ |
long stamp = locker.call(); |
1463 |
+ |
try { |
1464 |
+ |
assertTrue(isWriteLockStamp(stamp)); |
1465 |
+ |
assertTrue(sl.isWriteLocked()); |
1466 |
+ |
assertFalse(isReadLockStamp(stamp)); |
1467 |
+ |
assertFalse(sl.isReadLocked()); |
1468 |
+ |
assertEquals(0, sl.getReadLockCount()); |
1469 |
+ |
assertTrue(sl.validate(stamp)); |
1470 |
+ |
} finally { |
1471 |
+ |
unlocker.accept(stamp); |
1472 |
+ |
} |
1473 |
+ |
} |
1474 |
+ |
}; |
1475 |
+ |
final Action reader = () -> { |
1476 |
+ |
// repeatedly acquires read lock |
1477 |
+ |
var locker = chooseRandomly(stampedReadLockers); |
1478 |
+ |
var unlocker = chooseRandomly(stampedReadUnlockers); |
1479 |
+ |
while (!done.getAcquire()) { |
1480 |
+ |
long stamp = locker.call(); |
1481 |
+ |
try { |
1482 |
+ |
assertFalse(isWriteLockStamp(stamp)); |
1483 |
+ |
assertFalse(sl.isWriteLocked()); |
1484 |
+ |
assertTrue(isReadLockStamp(stamp)); |
1485 |
+ |
assertTrue(sl.isReadLocked()); |
1486 |
+ |
assertTrue(sl.getReadLockCount() > 0); |
1487 |
+ |
assertTrue(sl.validate(stamp)); |
1488 |
+ |
} finally { |
1489 |
+ |
unlocker.accept(stamp); |
1490 |
+ |
} |
1491 |
+ |
} |
1492 |
+ |
}; |
1493 |
+ |
for (int i = nTasks; i--> 0; ) { |
1494 |
+ |
Action task = chooseRandomly(writer, reader); |
1495 |
+ |
futures.add(CompletableFuture.runAsync(checkedRunnable(task))); |
1496 |
+ |
} |
1497 |
+ |
Thread.sleep(testDurationMillis); |
1498 |
+ |
done.setRelease(true); |
1499 |
+ |
for (var future : futures) |
1500 |
+ |
checkTimedGet(future, null); |
1501 |
+ |
} |
1502 |
+ |
|
1503 |
|
} |