ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
Revision: 1.47
Committed: Tue Jan 26 13:33:06 2021 UTC (3 years, 2 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.46: +1 -1 lines
Log Message:
Replace Integer with Item class

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 releaseReadLock(lock, s);
707 }
708
709 /**
710 * tryOptimisticRead succeeds and validates if unlocked, fails if
711 * exclusively locked
712 */
713 public void testValidateOptimistic() throws InterruptedException {
714 StampedLock lock = new StampedLock();
715
716 assertValid(lock, lock.tryOptimisticRead());
717
718 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
719 long s = assertValid(lock, writeLocker.apply(lock));
720 assertEquals(0L, lock.tryOptimisticRead());
721 releaseWriteLock(lock, s);
722 }
723
724 for (Function<StampedLock, Long> readLocker : readLockers()) {
725 long s = assertValid(lock, readLocker.apply(lock));
726 long p = assertValid(lock, lock.tryOptimisticRead());
727 releaseReadLock(lock, s);
728 assertTrue(lock.validate(p));
729 }
730
731 assertValid(lock, lock.tryOptimisticRead());
732 }
733
734 /**
735 * tryOptimisticRead stamp does not validate if a write lock intervenes
736 */
737 public void testValidateOptimisticWriteLocked() {
738 final StampedLock lock = new StampedLock();
739 final long p = assertValid(lock, lock.tryOptimisticRead());
740 final long s = assertValid(lock, lock.writeLock());
741 assertFalse(lock.validate(p));
742 assertEquals(0L, lock.tryOptimisticRead());
743 assertTrue(lock.validate(s));
744 lock.unlockWrite(s);
745 }
746
747 /**
748 * tryOptimisticRead stamp does not validate if a write lock
749 * intervenes in another thread
750 */
751 public void testValidateOptimisticWriteLocked2()
752 throws InterruptedException {
753 final CountDownLatch locked = new CountDownLatch(1);
754 final StampedLock lock = new StampedLock();
755 final long p = assertValid(lock, lock.tryOptimisticRead());
756
757 Thread t = newStartedThread(new CheckedInterruptedRunnable() {
758 public void realRun() throws InterruptedException {
759 lock.writeLockInterruptibly();
760 locked.countDown();
761 lock.writeLockInterruptibly();
762 }});
763
764 await(locked);
765 assertFalse(lock.validate(p));
766 assertEquals(0L, lock.tryOptimisticRead());
767 assertThreadBlocks(t, Thread.State.WAITING);
768 t.interrupt();
769 awaitTermination(t);
770 assertTrue(lock.isWriteLocked());
771 }
772
773 /**
774 * tryConvertToOptimisticRead succeeds and validates if successfully locked
775 */
776 public void testTryConvertToOptimisticRead() throws InterruptedException {
777 StampedLock lock = new StampedLock();
778 long s, p, q;
779 assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
780
781 s = assertValid(lock, lock.tryOptimisticRead());
782 assertEquals(s, lock.tryConvertToOptimisticRead(s));
783 assertTrue(lock.validate(s));
784
785 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
786 s = assertValid(lock, writeLocker.apply(lock));
787 p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
788 assertFalse(lock.validate(s));
789 assertTrue(lock.validate(p));
790 assertUnlocked(lock);
791 }
792
793 for (Function<StampedLock, Long> readLocker : readLockers()) {
794 s = assertValid(lock, readLocker.apply(lock));
795 q = assertValid(lock, lock.tryOptimisticRead());
796 assertEquals(q, lock.tryConvertToOptimisticRead(q));
797 assertTrue(lock.validate(q));
798 assertTrue(lock.isReadLocked());
799 p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
800 assertTrue(lock.validate(p));
801 assertTrue(lock.validate(s));
802 assertUnlocked(lock);
803 assertEquals(q, lock.tryConvertToOptimisticRead(q));
804 assertTrue(lock.validate(q));
805 }
806 }
807
808 /**
809 * tryConvertToReadLock succeeds for valid stamps
810 */
811 public void testTryConvertToReadLock() throws InterruptedException {
812 StampedLock lock = new StampedLock();
813 long s, p;
814
815 assertEquals(0L, lock.tryConvertToReadLock(0L));
816
817 s = assertValid(lock, lock.tryOptimisticRead());
818 p = assertValid(lock, lock.tryConvertToReadLock(s));
819 assertTrue(lock.isReadLocked());
820 assertEquals(1, lock.getReadLockCount());
821 assertTrue(lock.validate(s));
822 lock.unlockRead(p);
823
824 s = assertValid(lock, lock.tryOptimisticRead());
825 lock.readLock();
826 p = assertValid(lock, lock.tryConvertToReadLock(s));
827 assertTrue(lock.isReadLocked());
828 assertEquals(2, lock.getReadLockCount());
829 lock.unlockRead(p);
830 lock.unlockRead(p);
831 assertUnlocked(lock);
832
833 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
834 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
835 s = assertValid(lock, writeLocker.apply(lock));
836 p = assertValid(lock, lock.tryConvertToReadLock(s));
837 assertFalse(lock.validate(s));
838 assertTrue(lock.isReadLocked());
839 assertEquals(1, lock.getReadLockCount());
840 readUnlocker.accept(lock, p);
841 }
842
843 for (Function<StampedLock, Long> readLocker : readLockers()) {
844 s = assertValid(lock, readLocker.apply(lock));
845 assertEquals(s, lock.tryConvertToReadLock(s));
846 assertTrue(lock.validate(s));
847 assertTrue(lock.isReadLocked());
848 assertEquals(1, lock.getReadLockCount());
849 readUnlocker.accept(lock, s);
850 }
851 }
852 }
853
854 /**
855 * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
856 */
857 public void testTryConvertToWriteLock() throws InterruptedException {
858 StampedLock lock = new StampedLock();
859 long s, p;
860
861 assertEquals(0L, lock.tryConvertToWriteLock(0L));
862
863 assertTrue((s = lock.tryOptimisticRead()) != 0L);
864 assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
865 assertTrue(lock.isWriteLocked());
866 lock.unlockWrite(p);
867
868 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
869 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
870 s = assertValid(lock, writeLocker.apply(lock));
871 assertEquals(s, lock.tryConvertToWriteLock(s));
872 assertTrue(lock.validate(s));
873 assertTrue(lock.isWriteLocked());
874 writeUnlocker.accept(lock, s);
875 }
876
877 for (Function<StampedLock, Long> readLocker : readLockers()) {
878 s = assertValid(lock, readLocker.apply(lock));
879 p = assertValid(lock, lock.tryConvertToWriteLock(s));
880 assertFalse(lock.validate(s));
881 assertTrue(lock.validate(p));
882 assertTrue(lock.isWriteLocked());
883 writeUnlocker.accept(lock, p);
884 }
885 }
886
887 // failure if multiply read locked
888 for (Function<StampedLock, Long> readLocker : readLockers()) {
889 s = assertValid(lock, readLocker.apply(lock));
890 p = assertValid(lock, readLocker.apply(lock));
891 assertEquals(0L, lock.tryConvertToWriteLock(s));
892 assertTrue(lock.validate(s));
893 assertTrue(lock.validate(p));
894 assertEquals(2, lock.getReadLockCount());
895 lock.unlock(p);
896 lock.unlock(s);
897 assertUnlocked(lock);
898 }
899 }
900
901 /**
902 * asWriteLock can be locked and unlocked
903 */
904 public void testAsWriteLock() throws Throwable {
905 StampedLock sl = new StampedLock();
906 Lock lock = sl.asWriteLock();
907 for (Action locker : lockLockers(lock)) {
908 locker.run();
909 assertTrue(sl.isWriteLocked());
910 assertFalse(sl.isReadLocked());
911 assertFalse(lock.tryLock());
912 lock.unlock();
913 assertUnlocked(sl);
914 }
915 }
916
917 /**
918 * asReadLock can be locked and unlocked
919 */
920 public void testAsReadLock() throws Throwable {
921 StampedLock sl = new StampedLock();
922 Lock lock = sl.asReadLock();
923 for (Action locker : lockLockers(lock)) {
924 locker.run();
925 assertTrue(sl.isReadLocked());
926 assertFalse(sl.isWriteLocked());
927 assertEquals(1, sl.getReadLockCount());
928 locker.run();
929 assertTrue(sl.isReadLocked());
930 assertEquals(2, sl.getReadLockCount());
931 lock.unlock();
932 lock.unlock();
933 assertUnlocked(sl);
934 }
935 }
936
937 /**
938 * asReadWriteLock.writeLock can be locked and unlocked
939 */
940 public void testAsReadWriteLockWriteLock() throws Throwable {
941 StampedLock sl = new StampedLock();
942 Lock lock = sl.asReadWriteLock().writeLock();
943 for (Action locker : lockLockers(lock)) {
944 locker.run();
945 assertTrue(sl.isWriteLocked());
946 assertFalse(sl.isReadLocked());
947 assertFalse(lock.tryLock());
948 lock.unlock();
949 assertUnlocked(sl);
950 }
951 }
952
953 /**
954 * asReadWriteLock.readLock can be locked and unlocked
955 */
956 public void testAsReadWriteLockReadLock() throws Throwable {
957 StampedLock sl = new StampedLock();
958 Lock lock = sl.asReadWriteLock().readLock();
959 for (Action locker : lockLockers(lock)) {
960 locker.run();
961 assertTrue(sl.isReadLocked());
962 assertFalse(sl.isWriteLocked());
963 assertEquals(1, sl.getReadLockCount());
964 locker.run();
965 assertTrue(sl.isReadLocked());
966 assertEquals(2, sl.getReadLockCount());
967 lock.unlock();
968 lock.unlock();
969 assertUnlocked(sl);
970 }
971 }
972
973 /**
974 * Lock.newCondition throws UnsupportedOperationException
975 */
976 public void testLockViewsDoNotSupportConditions() {
977 StampedLock sl = new StampedLock();
978 assertThrows(UnsupportedOperationException.class,
979 () -> sl.asWriteLock().newCondition(),
980 () -> sl.asReadLock().newCondition(),
981 () -> sl.asReadWriteLock().writeLock().newCondition(),
982 () -> sl.asReadWriteLock().readLock().newCondition());
983 }
984
985 /**
986 * Passing optimistic read stamps to unlock operations result in
987 * IllegalMonitorStateException
988 */
989 public void testCannotUnlockOptimisticReadStamps() {
990 {
991 StampedLock sl = new StampedLock();
992 long stamp = assertValid(sl, sl.tryOptimisticRead());
993 assertThrows(IllegalMonitorStateException.class,
994 () -> sl.unlockRead(stamp));
995 }
996 {
997 StampedLock sl = new StampedLock();
998 long stamp = sl.tryOptimisticRead();
999 assertThrows(IllegalMonitorStateException.class,
1000 () -> sl.unlock(stamp));
1001 }
1002
1003 {
1004 StampedLock sl = new StampedLock();
1005 long stamp = sl.tryOptimisticRead();
1006 sl.writeLock();
1007 assertThrows(IllegalMonitorStateException.class,
1008 () -> sl.unlock(stamp));
1009 }
1010 {
1011 StampedLock sl = new StampedLock();
1012 sl.readLock();
1013 long stamp = assertValid(sl, sl.tryOptimisticRead());
1014 assertThrows(IllegalMonitorStateException.class,
1015 () -> sl.unlockRead(stamp));
1016 }
1017 {
1018 StampedLock sl = new StampedLock();
1019 sl.readLock();
1020 long stamp = assertValid(sl, sl.tryOptimisticRead());
1021 assertThrows(IllegalMonitorStateException.class,
1022 () -> sl.unlock(stamp));
1023 }
1024
1025 {
1026 StampedLock sl = new StampedLock();
1027 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1028 assertValid(sl, stamp);
1029 sl.writeLock();
1030 assertThrows(IllegalMonitorStateException.class,
1031 () -> sl.unlockWrite(stamp));
1032 }
1033 {
1034 StampedLock sl = new StampedLock();
1035 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1036 sl.writeLock();
1037 assertThrows(IllegalMonitorStateException.class,
1038 () -> sl.unlock(stamp));
1039 }
1040 {
1041 StampedLock sl = new StampedLock();
1042 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1043 sl.readLock();
1044 assertThrows(IllegalMonitorStateException.class,
1045 () -> sl.unlockRead(stamp));
1046 }
1047 {
1048 StampedLock sl = new StampedLock();
1049 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1050 sl.readLock();
1051 assertThrows(IllegalMonitorStateException.class,
1052 () -> sl.unlock(stamp));
1053 }
1054
1055 {
1056 StampedLock sl = new StampedLock();
1057 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1058 assertValid(sl, stamp);
1059 sl.writeLock();
1060 assertThrows(IllegalMonitorStateException.class,
1061 () -> sl.unlockWrite(stamp));
1062 }
1063 {
1064 StampedLock sl = new StampedLock();
1065 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1066 sl.writeLock();
1067 assertThrows(IllegalMonitorStateException.class,
1068 () -> sl.unlock(stamp));
1069 }
1070 {
1071 StampedLock sl = new StampedLock();
1072 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1073 sl.readLock();
1074 assertThrows(IllegalMonitorStateException.class,
1075 () -> sl.unlockRead(stamp));
1076 }
1077 {
1078 StampedLock sl = new StampedLock();
1079 sl.readLock();
1080 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1081 assertValid(sl, stamp);
1082 sl.readLock();
1083 assertThrows(IllegalMonitorStateException.class,
1084 () -> sl.unlockRead(stamp));
1085 }
1086 {
1087 StampedLock sl = new StampedLock();
1088 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1089 sl.readLock();
1090 assertThrows(IllegalMonitorStateException.class,
1091 () -> sl.unlock(stamp));
1092 }
1093 {
1094 StampedLock sl = new StampedLock();
1095 sl.readLock();
1096 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1097 sl.readLock();
1098 assertThrows(IllegalMonitorStateException.class,
1099 () -> sl.unlock(stamp));
1100 }
1101 }
1102
1103 static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
1104 try { return sl.writeLockInterruptibly(); }
1105 catch (InterruptedException ex) { throw new AssertionError(ex); }
1106 }
1107
1108 static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1109 try { return sl.tryWriteLock(time, unit); }
1110 catch (InterruptedException ex) { throw new AssertionError(ex); }
1111 }
1112
1113 static long readLockInterruptiblyUninterrupted(StampedLock sl) {
1114 try { return sl.readLockInterruptibly(); }
1115 catch (InterruptedException ex) { throw new AssertionError(ex); }
1116 }
1117
1118 static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1119 try { return sl.tryReadLock(time, unit); }
1120 catch (InterruptedException ex) { throw new AssertionError(ex); }
1121 }
1122
1123 /**
1124 * Invalid stamps result in IllegalMonitorStateException
1125 */
1126 public void testInvalidStampsThrowIllegalMonitorStateException() {
1127 final StampedLock sl = new StampedLock();
1128
1129 assertThrows(IllegalMonitorStateException.class,
1130 () -> sl.unlockWrite(0L),
1131 () -> sl.unlockRead(0L),
1132 () -> sl.unlock(0L));
1133
1134 final long optimisticStamp = sl.tryOptimisticRead();
1135 final long readStamp = sl.readLock();
1136 sl.unlockRead(readStamp);
1137 final long writeStamp = sl.writeLock();
1138 sl.unlockWrite(writeStamp);
1139 assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1140 final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1141 final Runnable assertNoLongerValidStampsThrow = () -> {
1142 for (long noLongerValidStamp : noLongerValidStamps)
1143 assertThrows(IllegalMonitorStateException.class,
1144 () -> sl.unlockWrite(noLongerValidStamp),
1145 () -> sl.unlockRead(noLongerValidStamp),
1146 () -> sl.unlock(noLongerValidStamp));
1147 };
1148 assertNoLongerValidStampsThrow.run();
1149
1150 for (Function<StampedLock, Long> readLocker : readLockers())
1151 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1152 final long stamp = readLocker.apply(sl);
1153 assertValid(sl, stamp);
1154 assertNoLongerValidStampsThrow.run();
1155 assertThrows(IllegalMonitorStateException.class,
1156 () -> sl.unlockWrite(stamp),
1157 () -> sl.unlockRead(sl.tryOptimisticRead()),
1158 () -> sl.unlockRead(0L));
1159 readUnlocker.accept(sl, stamp);
1160 assertUnlocked(sl);
1161 assertNoLongerValidStampsThrow.run();
1162 }
1163
1164 for (Function<StampedLock, Long> writeLocker : writeLockers())
1165 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1166 final long stamp = writeLocker.apply(sl);
1167 assertValid(sl, stamp);
1168 assertNoLongerValidStampsThrow.run();
1169 assertThrows(IllegalMonitorStateException.class,
1170 () -> sl.unlockRead(stamp),
1171 () -> sl.unlockWrite(0L));
1172 writeUnlocker.accept(sl, stamp);
1173 assertUnlocked(sl);
1174 assertNoLongerValidStampsThrow.run();
1175 }
1176 }
1177
1178 /**
1179 * Read locks can be very deeply nested
1180 */
1181 public void testDeeplyNestedReadLocks() {
1182 final StampedLock lock = new StampedLock();
1183 final int depth = 300;
1184 final long[] stamps = new long[depth];
1185 final List<Function<StampedLock, Long>> readLockers = readLockers();
1186 final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1187 for (int i = 0; i < depth; i++) {
1188 Function<StampedLock, Long> readLocker
1189 = readLockers.get(i % readLockers.size());
1190 long stamp = readLocker.apply(lock);
1191 assertEquals(i + 1, lock.getReadLockCount());
1192 assertTrue(lock.isReadLocked());
1193 stamps[i] = stamp;
1194 }
1195 for (int i = 0; i < depth; i++) {
1196 BiConsumer<StampedLock, Long> readUnlocker
1197 = readUnlockers.get(i % readUnlockers.size());
1198 assertEquals(depth - i, lock.getReadLockCount());
1199 assertTrue(lock.isReadLocked());
1200 readUnlocker.accept(lock, stamps[depth - 1 - i]);
1201 }
1202 assertUnlocked(lock);
1203 }
1204
1205 /**
1206 * Stamped locks are not reentrant.
1207 */
1208 public void testNonReentrant() throws InterruptedException {
1209 final StampedLock lock = new StampedLock();
1210 long stamp;
1211
1212 stamp = lock.writeLock();
1213 assertValid(lock, stamp);
1214 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1215 assertEquals(0L, lock.tryReadLock(0L, DAYS));
1216 assertValid(lock, stamp);
1217 lock.unlockWrite(stamp);
1218
1219 stamp = lock.tryWriteLock(1L, DAYS);
1220 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1221 assertValid(lock, stamp);
1222 lock.unlockWrite(stamp);
1223
1224 stamp = lock.readLock();
1225 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1226 assertValid(lock, stamp);
1227 lock.unlockRead(stamp);
1228 }
1229
1230 /**
1231 * """StampedLocks have no notion of ownership. Locks acquired in
1232 * one thread can be released or converted in another."""
1233 */
1234 public void testNoOwnership() throws Throwable {
1235 ArrayList<Future<?>> futures = new ArrayList<>();
1236 for (Function<StampedLock, Long> writeLocker : writeLockers())
1237 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1238 StampedLock lock = new StampedLock();
1239 long stamp = writeLocker.apply(lock);
1240 futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1241 public void realRun() {
1242 writeUnlocker.accept(lock, stamp);
1243 assertUnlocked(lock);
1244 assertFalse(lock.validate(stamp));
1245 }}));
1246 }
1247 for (Future<?> future : futures)
1248 assertNull(future.get());
1249 }
1250
1251 /** Tries out sample usage code from StampedLock javadoc. */
1252 public void testSampleUsage() throws Throwable {
1253 class Point {
1254 private double x, y;
1255 private final StampedLock sl = new StampedLock();
1256
1257 void move(double deltaX, double deltaY) { // an exclusively locked method
1258 long stamp = sl.writeLock();
1259 try {
1260 x += deltaX;
1261 y += deltaY;
1262 } finally {
1263 sl.unlockWrite(stamp);
1264 }
1265 }
1266
1267 double distanceFromOrigin() { // A read-only method
1268 double currentX, currentY;
1269 long stamp = sl.tryOptimisticRead();
1270 do {
1271 if (stamp == 0L)
1272 stamp = sl.readLock();
1273 try {
1274 // possibly racy reads
1275 currentX = x;
1276 currentY = y;
1277 } finally {
1278 stamp = sl.tryConvertToOptimisticRead(stamp);
1279 }
1280 } while (stamp == 0);
1281 return Math.hypot(currentX, currentY);
1282 }
1283
1284 double distanceFromOrigin2() {
1285 long stamp = sl.tryOptimisticRead();
1286 try {
1287 retryHoldingLock:
1288 for (;; stamp = sl.readLock()) {
1289 if (stamp == 0L)
1290 continue retryHoldingLock;
1291 // possibly racy reads
1292 double currentX = x;
1293 double currentY = y;
1294 if (!sl.validate(stamp))
1295 continue retryHoldingLock;
1296 return Math.hypot(currentX, currentY);
1297 }
1298 } finally {
1299 if (StampedLock.isReadLockStamp(stamp))
1300 sl.unlockRead(stamp);
1301 }
1302 }
1303
1304 void moveIfAtOrigin(double newX, double newY) {
1305 long stamp = sl.readLock();
1306 try {
1307 while (x == 0.0 && y == 0.0) {
1308 long ws = sl.tryConvertToWriteLock(stamp);
1309 if (ws != 0L) {
1310 stamp = ws;
1311 x = newX;
1312 y = newY;
1313 return;
1314 }
1315 else {
1316 sl.unlockRead(stamp);
1317 stamp = sl.writeLock();
1318 }
1319 }
1320 } finally {
1321 sl.unlock(stamp);
1322 }
1323 }
1324 }
1325
1326 Point p = new Point();
1327 p.move(3.0, 4.0);
1328 assertEquals(5.0, p.distanceFromOrigin());
1329 p.moveIfAtOrigin(5.0, 12.0);
1330 assertEquals(5.0, p.distanceFromOrigin2());
1331 }
1332
1333 /**
1334 * Stamp inspection methods work as expected, and do not inspect
1335 * the state of the lock itself.
1336 */
1337 public void testStampStateInspectionMethods() {
1338 StampedLock lock = new StampedLock();
1339
1340 assertFalse(isWriteLockStamp(0L));
1341 assertFalse(isReadLockStamp(0L));
1342 assertFalse(isLockStamp(0L));
1343 assertFalse(isOptimisticReadStamp(0L));
1344
1345 {
1346 long stamp = lock.writeLock();
1347 for (int i = 0; i < 2; i++) {
1348 assertTrue(isWriteLockStamp(stamp));
1349 assertFalse(isReadLockStamp(stamp));
1350 assertTrue(isLockStamp(stamp));
1351 assertFalse(isOptimisticReadStamp(stamp));
1352 if (i == 0)
1353 lock.unlockWrite(stamp);
1354 }
1355 }
1356
1357 {
1358 long stamp = lock.readLock();
1359 for (int i = 0; i < 2; i++) {
1360 assertFalse(isWriteLockStamp(stamp));
1361 assertTrue(isReadLockStamp(stamp));
1362 assertTrue(isLockStamp(stamp));
1363 assertFalse(isOptimisticReadStamp(stamp));
1364 if (i == 0)
1365 lock.unlockRead(stamp);
1366 }
1367 }
1368
1369 {
1370 long optimisticStamp = lock.tryOptimisticRead();
1371 long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1372 long writeStamp = lock.tryConvertToWriteLock(readStamp);
1373 for (int i = 0; i < 2; i++) {
1374 assertFalse(isWriteLockStamp(optimisticStamp));
1375 assertFalse(isReadLockStamp(optimisticStamp));
1376 assertFalse(isLockStamp(optimisticStamp));
1377 assertTrue(isOptimisticReadStamp(optimisticStamp));
1378
1379 assertFalse(isWriteLockStamp(readStamp));
1380 assertTrue(isReadLockStamp(readStamp));
1381 assertTrue(isLockStamp(readStamp));
1382 assertFalse(isOptimisticReadStamp(readStamp));
1383
1384 assertTrue(isWriteLockStamp(writeStamp));
1385 assertFalse(isReadLockStamp(writeStamp));
1386 assertTrue(isLockStamp(writeStamp));
1387 assertFalse(isOptimisticReadStamp(writeStamp));
1388 if (i == 0)
1389 lock.unlockWrite(writeStamp);
1390 }
1391 }
1392 }
1393
1394 /**
1395 * Multiple threads repeatedly contend for the same lock.
1396 */
1397 public void testConcurrentAccess() throws Exception {
1398 final StampedLock sl = new StampedLock();
1399 final Lock wl = sl.asWriteLock();
1400 final Lock rl = sl.asReadLock();
1401 final long testDurationMillis = expensiveTests ? 1000 : 2;
1402 final int nTasks = ThreadLocalRandom.current().nextInt(1, 10);
1403 final AtomicBoolean done = new AtomicBoolean(false);
1404 final List<CompletableFuture<?>> futures = new ArrayList<>();
1405 final List<Callable<Long>> stampedWriteLockers = List.of(
1406 () -> sl.writeLock(),
1407 () -> writeLockInterruptiblyUninterrupted(sl),
1408 () -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1409 () -> {
1410 long stamp;
1411 do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); }
1412 while (stamp == 0L);
1413 return stamp;
1414 },
1415 () -> {
1416 long stamp;
1417 do { stamp = sl.tryWriteLock(); } while (stamp == 0L);
1418 return stamp;
1419 },
1420 () -> {
1421 long stamp;
1422 do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L);
1423 return stamp;
1424 });
1425 final List<Callable<Long>> stampedReadLockers = List.of(
1426 () -> sl.readLock(),
1427 () -> readLockInterruptiblyUninterrupted(sl),
1428 () -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS),
1429 () -> {
1430 long stamp;
1431 do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); }
1432 while (stamp == 0L);
1433 return stamp;
1434 },
1435 () -> {
1436 long stamp;
1437 do { stamp = sl.tryReadLock(); } while (stamp == 0L);
1438 return stamp;
1439 },
1440 () -> {
1441 long stamp;
1442 do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L);
1443 return stamp;
1444 });
1445 final List<Consumer<Long>> stampedWriteUnlockers = List.of(
1446 stamp -> sl.unlockWrite(stamp),
1447 stamp -> sl.unlock(stamp),
1448 stamp -> assertTrue(sl.tryUnlockWrite()),
1449 stamp -> wl.unlock(),
1450 stamp -> sl.tryConvertToOptimisticRead(stamp));
1451 final List<Consumer<Long>> stampedReadUnlockers = List.of(
1452 stamp -> sl.unlockRead(stamp),
1453 stamp -> sl.unlock(stamp),
1454 stamp -> assertTrue(sl.tryUnlockRead()),
1455 stamp -> rl.unlock(),
1456 stamp -> sl.tryConvertToOptimisticRead(stamp));
1457 final Action writer = () -> {
1458 // repeatedly acquires write lock
1459 var locker = chooseRandomly(stampedWriteLockers);
1460 var unlocker = chooseRandomly(stampedWriteUnlockers);
1461 while (!done.getAcquire()) {
1462 long stamp = locker.call();
1463 try {
1464 assertTrue(isWriteLockStamp(stamp));
1465 assertTrue(sl.isWriteLocked());
1466 assertFalse(isReadLockStamp(stamp));
1467 assertFalse(sl.isReadLocked());
1468 assertEquals(0, sl.getReadLockCount());
1469 assertTrue(sl.validate(stamp));
1470 } finally {
1471 unlocker.accept(stamp);
1472 }
1473 }
1474 };
1475 final Action reader = () -> {
1476 // repeatedly acquires read lock
1477 var locker = chooseRandomly(stampedReadLockers);
1478 var unlocker = chooseRandomly(stampedReadUnlockers);
1479 while (!done.getAcquire()) {
1480 long stamp = locker.call();
1481 try {
1482 assertFalse(isWriteLockStamp(stamp));
1483 assertFalse(sl.isWriteLocked());
1484 assertTrue(isReadLockStamp(stamp));
1485 assertTrue(sl.isReadLocked());
1486 assertTrue(sl.getReadLockCount() > 0);
1487 assertTrue(sl.validate(stamp));
1488 } finally {
1489 unlocker.accept(stamp);
1490 }
1491 }
1492 };
1493 for (int i = nTasks; i--> 0; ) {
1494 Action task = chooseRandomly(writer, reader);
1495 futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
1496 }
1497 Thread.sleep(testDurationMillis);
1498 done.setRelease(true);
1499 for (var future : futures)
1500 checkTimedGet(future, null);
1501 }
1502
1503 }