8 |
|
import static java.util.concurrent.TimeUnit.DAYS; |
9 |
|
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
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)); |
80 |
< |
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())); |
91 |
< |
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))); |
101 |
< |
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())); |
112 |
< |
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))); |
122 |
< |
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 |
|
/** |
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 |
|
/** |
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); |
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 |
< |
|
992 |
< |
() -> { |
993 |
< |
StampedLock sl = new StampedLock(); |
994 |
< |
long stamp = sl.tryOptimisticRead(); |
995 |
< |
sl.writeLock(); |
996 |
< |
sl.unlock(stamp); |
997 |
< |
}, |
998 |
< |
() -> { |
999 |
< |
StampedLock sl = new StampedLock(); |
1000 |
< |
sl.readLock(); |
1001 |
< |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
1002 |
< |
sl.unlockRead(stamp); |
1003 |
< |
}, |
1004 |
< |
() -> { |
1005 |
< |
StampedLock sl = new StampedLock(); |
1006 |
< |
sl.readLock(); |
1007 |
< |
long stamp = assertValid(sl, sl.tryOptimisticRead()); |
1008 |
< |
sl.unlock(stamp); |
1009 |
< |
}, |
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(); |
1032 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); |
1033 |
< |
sl.readLock(); |
1034 |
< |
sl.unlock(stamp); |
1035 |
< |
}, |
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(); |
1066 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1067 |
< |
sl.readLock(); |
1068 |
< |
sl.unlock(stamp); |
1069 |
< |
}, |
1070 |
< |
() -> { |
1071 |
< |
StampedLock sl = new StampedLock(); |
1072 |
< |
sl.readLock(); |
1073 |
< |
long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); |
1074 |
< |
sl.readLock(); |
1075 |
< |
sl.unlock(stamp); |
1076 |
< |
}, |
1077 |
< |
}; |
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) { |
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 |
|
} |