ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
Revision: 1.45
Committed: Wed Aug 12 16:12:23 2020 UTC (3 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.44: +6 -2 lines
Log Message:
fix errorprone [UnusedVariable]

File Contents

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