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