ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
Revision: 1.41
Committed: Wed Oct 4 03:49:33 2017 UTC (6 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.40: +109 -0 lines
Log Message:
8187941: Add StampedLock stamp inspection methods

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.CountDownLatch;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.locks.Lock;
22 import java.util.concurrent.locks.StampedLock;
23 import java.util.function.BiConsumer;
24 import java.util.function.Function;
25
26 import junit.framework.Test;
27 import junit.framework.TestSuite;
28
29 public class StampedLockTest extends JSR166TestCase {
30 public static void main(String[] args) {
31 main(suite(), args);
32 }
33 public static Test suite() {
34 return new TestSuite(StampedLockTest.class);
35 }
36
37 /**
38 * Releases write lock, checking isWriteLocked before and after
39 */
40 void releaseWriteLock(StampedLock lock, long stamp) {
41 assertTrue(lock.isWriteLocked());
42 assertValid(lock, stamp);
43 lock.unlockWrite(stamp);
44 assertFalse(lock.isWriteLocked());
45 assertFalse(lock.validate(stamp));
46 }
47
48 /**
49 * Releases read lock, checking isReadLocked before and after
50 */
51 void releaseReadLock(StampedLock lock, long stamp) {
52 assertTrue(lock.isReadLocked());
53 assertValid(lock, stamp);
54 lock.unlockRead(stamp);
55 assertFalse(lock.isReadLocked());
56 assertTrue(lock.validate(stamp));
57 }
58
59 long assertNonZero(long v) {
60 assertTrue(v != 0L);
61 return v;
62 }
63
64 long assertValid(StampedLock lock, long stamp) {
65 assertTrue(stamp != 0L);
66 assertTrue(lock.validate(stamp));
67 return stamp;
68 }
69
70 void assertUnlocked(StampedLock lock) {
71 assertFalse(lock.isReadLocked());
72 assertFalse(lock.isWriteLocked());
73 assertEquals(0, lock.getReadLockCount());
74 assertValid(lock, lock.tryOptimisticRead());
75 }
76
77 List<Action> lockLockers(Lock lock) {
78 List<Action> lockers = new ArrayList<>();
79 lockers.add(() -> lock.lock());
80 lockers.add(() -> lock.lockInterruptibly());
81 lockers.add(() -> lock.tryLock());
82 lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS));
83 lockers.add(() -> lock.tryLock(0L, DAYS));
84 lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS));
85 return lockers;
86 }
87
88 List<Function<StampedLock, Long>> readLockers() {
89 List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
90 readLockers.add(sl -> sl.readLock());
91 readLockers.add(sl -> sl.tryReadLock());
92 readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
93 readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
94 readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
95 readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
96 return readLockers;
97 }
98
99 List<BiConsumer<StampedLock, Long>> readUnlockers() {
100 List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
101 readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
102 readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
103 readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
104 readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
105 readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
106 return readUnlockers;
107 }
108
109 List<Function<StampedLock, Long>> writeLockers() {
110 List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
111 writeLockers.add(sl -> sl.writeLock());
112 writeLockers.add(sl -> sl.tryWriteLock());
113 writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
114 writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
115 writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
116 writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
117 return writeLockers;
118 }
119
120 List<BiConsumer<StampedLock, Long>> writeUnlockers() {
121 List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
122 writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
123 writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
124 writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
125 writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
126 writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp)));
127 return writeUnlockers;
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 s = 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
363 /**
364 * interruptible operations throw InterruptedException when read locked and interrupted
365 */
366 public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
367 final StampedLock lock = new StampedLock();
368 long s = lock.readLock();
369
370 Action[] interruptibleLockBlockingActions = {
371 () -> lock.writeLockInterruptibly(),
372 () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS),
373 () -> lock.asWriteLock().lockInterruptibly(),
374 () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS),
375 };
376 shuffle(interruptibleLockBlockingActions);
377
378 assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions);
379 }
380
381 /**
382 * Non-interruptible operations ignore and preserve interrupt status
383 */
384 public void testNonInterruptibleOperationsIgnoreInterrupts() {
385 final StampedLock lock = new StampedLock();
386 Thread.currentThread().interrupt();
387
388 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
389 long s = assertValid(lock, lock.readLock());
390 readUnlocker.accept(lock, s);
391 s = assertValid(lock, lock.tryReadLock());
392 readUnlocker.accept(lock, s);
393 }
394
395 lock.asReadLock().lock();
396 lock.asReadLock().unlock();
397
398 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
399 long s = assertValid(lock, lock.writeLock());
400 writeUnlocker.accept(lock, s);
401 s = assertValid(lock, lock.tryWriteLock());
402 writeUnlocker.accept(lock, s);
403 }
404
405 lock.asWriteLock().lock();
406 lock.asWriteLock().unlock();
407
408 assertTrue(Thread.interrupted());
409 }
410
411 /**
412 * tryWriteLock on an unlocked lock succeeds
413 */
414 public void testTryWriteLock() {
415 final StampedLock lock = new StampedLock();
416 long s = lock.tryWriteLock();
417 assertTrue(s != 0L);
418 assertTrue(lock.isWriteLocked());
419 assertEquals(0L, lock.tryWriteLock());
420 releaseWriteLock(lock, s);
421 }
422
423 /**
424 * tryWriteLock fails if locked
425 */
426 public void testTryWriteLockWhenLocked() {
427 final StampedLock lock = new StampedLock();
428 long s = lock.writeLock();
429 Thread t = newStartedThread(new CheckedRunnable() {
430 public void realRun() {
431 assertEquals(0L, lock.tryWriteLock());
432 }});
433
434 assertEquals(0L, lock.tryWriteLock());
435 awaitTermination(t);
436 releaseWriteLock(lock, s);
437 }
438
439 /**
440 * tryReadLock fails if write-locked
441 */
442 public void testTryReadLockWhenLocked() {
443 final StampedLock lock = new StampedLock();
444 long s = lock.writeLock();
445 Thread t = newStartedThread(new CheckedRunnable() {
446 public void realRun() {
447 assertEquals(0L, lock.tryReadLock());
448 }});
449
450 assertEquals(0L, lock.tryReadLock());
451 awaitTermination(t);
452 releaseWriteLock(lock, s);
453 }
454
455 /**
456 * Multiple threads can hold a read lock when not write-locked
457 */
458 public void testMultipleReadLocks() {
459 final StampedLock lock = new StampedLock();
460 final long s = lock.readLock();
461 Thread t = newStartedThread(new CheckedRunnable() {
462 public void realRun() throws InterruptedException {
463 long s2 = lock.tryReadLock();
464 assertValid(lock, s2);
465 lock.unlockRead(s2);
466 long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS);
467 assertValid(lock, s3);
468 lock.unlockRead(s3);
469 long s4 = lock.readLock();
470 assertValid(lock, s4);
471 lock.unlockRead(s4);
472 lock.asReadLock().lock();
473 lock.asReadLock().unlock();
474 lock.asReadLock().lockInterruptibly();
475 lock.asReadLock().unlock();
476 lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS);
477 lock.asReadLock().unlock();
478 }});
479
480 awaitTermination(t);
481 lock.unlockRead(s);
482 }
483
484 /**
485 * writeLock() succeeds only after a reading thread unlocks
486 */
487 public void testWriteAfterReadLock() throws InterruptedException {
488 final CountDownLatch aboutToLock = new CountDownLatch(1);
489 final StampedLock lock = new StampedLock();
490 long rs = lock.readLock();
491 Thread t = newStartedThread(new CheckedRunnable() {
492 public void realRun() {
493 aboutToLock.countDown();
494 long s = lock.writeLock();
495 assertTrue(lock.isWriteLocked());
496 assertFalse(lock.isReadLocked());
497 lock.unlockWrite(s);
498 }});
499
500 await(aboutToLock);
501 assertThreadBlocks(t, Thread.State.WAITING);
502 assertFalse(lock.isWriteLocked());
503 assertTrue(lock.isReadLocked());
504 lock.unlockRead(rs);
505 awaitTermination(t);
506 assertUnlocked(lock);
507 }
508
509 /**
510 * writeLock() succeeds only after reading threads unlock
511 */
512 public void testWriteAfterMultipleReadLocks() {
513 final StampedLock lock = new StampedLock();
514 long s = lock.readLock();
515 Thread t1 = newStartedThread(new CheckedRunnable() {
516 public void realRun() {
517 long rs = lock.readLock();
518 lock.unlockRead(rs);
519 }});
520
521 awaitTermination(t1);
522
523 Thread t2 = newStartedThread(new CheckedRunnable() {
524 public void realRun() {
525 long ws = lock.writeLock();
526 lock.unlockWrite(ws);
527 }});
528
529 assertTrue(lock.isReadLocked());
530 assertFalse(lock.isWriteLocked());
531 lock.unlockRead(s);
532 awaitTermination(t2);
533 assertUnlocked(lock);
534 }
535
536 /**
537 * readLock() succeed only after a writing thread unlocks
538 */
539 public void testReadAfterWriteLock() {
540 final StampedLock lock = new StampedLock();
541 final CountDownLatch threadsStarted = new CountDownLatch(2);
542 final long s = lock.writeLock();
543 final Runnable acquireReleaseReadLock = new CheckedRunnable() {
544 public void realRun() {
545 threadsStarted.countDown();
546 long rs = lock.readLock();
547 assertTrue(lock.isReadLocked());
548 assertFalse(lock.isWriteLocked());
549 lock.unlockRead(rs);
550 }};
551 Thread t1 = newStartedThread(acquireReleaseReadLock);
552 Thread t2 = newStartedThread(acquireReleaseReadLock);
553
554 await(threadsStarted);
555 assertThreadBlocks(t1, Thread.State.WAITING);
556 assertThreadBlocks(t2, Thread.State.WAITING);
557 assertTrue(lock.isWriteLocked());
558 assertFalse(lock.isReadLocked());
559 releaseWriteLock(lock, s);
560 awaitTermination(t1);
561 awaitTermination(t2);
562 assertUnlocked(lock);
563 }
564
565 /**
566 * tryReadLock succeeds if read locked but not write locked
567 */
568 public void testTryLockWhenReadLocked() {
569 final StampedLock lock = new StampedLock();
570 long s = lock.readLock();
571 Thread t = newStartedThread(new CheckedRunnable() {
572 public void realRun() {
573 long rs = lock.tryReadLock();
574 assertValid(lock, rs);
575 lock.unlockRead(rs);
576 }});
577
578 awaitTermination(t);
579 lock.unlockRead(s);
580 }
581
582 /**
583 * tryWriteLock fails when read locked
584 */
585 public void testTryWriteLockWhenReadLocked() {
586 final StampedLock lock = new StampedLock();
587 long s = lock.readLock();
588 Thread t = newStartedThread(new CheckedRunnable() {
589 public void realRun() {
590 threadAssertEquals(0L, lock.tryWriteLock());
591 }});
592
593 awaitTermination(t);
594 lock.unlockRead(s);
595 }
596
597 /**
598 * timed lock operations time out if lock not available
599 */
600 public void testTimedLock_Timeout() throws Exception {
601 ArrayList<Future<?>> futures = new ArrayList<>();
602
603 // Write locked
604 final StampedLock lock = new StampedLock();
605 long stamp = lock.writeLock();
606 assertEquals(0L, lock.tryReadLock(0L, DAYS));
607 assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS));
608 assertFalse(lock.asReadLock().tryLock(0L, DAYS));
609 assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS));
610 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
611 assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS));
612 assertFalse(lock.asWriteLock().tryLock(0L, DAYS));
613 assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
614
615 futures.add(cachedThreadPool.submit(new CheckedRunnable() {
616 public void realRun() throws InterruptedException {
617 long startTime = System.nanoTime();
618 assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS));
619 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
620 }}));
621
622 futures.add(cachedThreadPool.submit(new CheckedRunnable() {
623 public void realRun() throws InterruptedException {
624 long startTime = System.nanoTime();
625 assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS));
626 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
627 }}));
628
629 // Read locked
630 final StampedLock lock2 = new StampedLock();
631 long stamp2 = lock2.readLock();
632 assertEquals(0L, lock2.tryWriteLock(0L, DAYS));
633 assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS));
634 assertFalse(lock2.asWriteLock().tryLock(0L, DAYS));
635 assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS));
636
637 futures.add(cachedThreadPool.submit(new CheckedRunnable() {
638 public void realRun() throws InterruptedException {
639 long startTime = System.nanoTime();
640 assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS));
641 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
642 }}));
643
644 for (Future<?> future : futures)
645 assertNull(future.get());
646
647 releaseWriteLock(lock, stamp);
648 releaseReadLock(lock2, stamp2);
649 }
650
651 /**
652 * writeLockInterruptibly succeeds if unlocked
653 */
654 public void testWriteLockInterruptibly() throws InterruptedException {
655 final StampedLock lock = new StampedLock();
656 long s = lock.writeLockInterruptibly();
657 assertTrue(lock.isWriteLocked());
658 releaseWriteLock(lock, s);
659 }
660
661 /**
662 * readLockInterruptibly succeeds if lock free
663 */
664 public void testReadLockInterruptibly() throws InterruptedException {
665 final StampedLock lock = new StampedLock();
666
667 long s = assertValid(lock, lock.readLockInterruptibly());
668 assertTrue(lock.isReadLocked());
669 lock.unlockRead(s);
670
671 lock.asReadLock().lockInterruptibly();
672 assertTrue(lock.isReadLocked());
673 lock.asReadLock().unlock();
674 }
675
676 /**
677 * A serialized lock deserializes as unlocked
678 */
679 public void testSerialization() {
680 StampedLock lock = new StampedLock();
681 lock.writeLock();
682 StampedLock clone = serialClone(lock);
683 assertTrue(lock.isWriteLocked());
684 assertFalse(clone.isWriteLocked());
685 long s = clone.writeLock();
686 assertTrue(clone.isWriteLocked());
687 clone.unlockWrite(s);
688 assertFalse(clone.isWriteLocked());
689 }
690
691 /**
692 * toString indicates current lock state
693 */
694 public void testToString() {
695 StampedLock lock = new StampedLock();
696 assertTrue(lock.toString().contains("Unlocked"));
697 long s = lock.writeLock();
698 assertTrue(lock.toString().contains("Write-locked"));
699 lock.unlockWrite(s);
700 s = lock.readLock();
701 assertTrue(lock.toString().contains("Read-locks"));
702 }
703
704 /**
705 * tryOptimisticRead succeeds and validates if unlocked, fails if
706 * exclusively locked
707 */
708 public void testValidateOptimistic() throws InterruptedException {
709 StampedLock lock = new StampedLock();
710
711 assertValid(lock, lock.tryOptimisticRead());
712
713 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
714 long s = assertValid(lock, writeLocker.apply(lock));
715 assertEquals(0L, lock.tryOptimisticRead());
716 releaseWriteLock(lock, s);
717 }
718
719 for (Function<StampedLock, Long> readLocker : readLockers()) {
720 long s = assertValid(lock, readLocker.apply(lock));
721 long p = assertValid(lock, lock.tryOptimisticRead());
722 releaseReadLock(lock, s);
723 assertTrue(lock.validate(p));
724 }
725
726 assertValid(lock, lock.tryOptimisticRead());
727 }
728
729 /**
730 * tryOptimisticRead stamp does not validate if a write lock intervenes
731 */
732 public void testValidateOptimisticWriteLocked() {
733 final StampedLock lock = new StampedLock();
734 final long p = assertValid(lock, lock.tryOptimisticRead());
735 final long s = assertValid(lock, lock.writeLock());
736 assertFalse(lock.validate(p));
737 assertEquals(0L, lock.tryOptimisticRead());
738 assertTrue(lock.validate(s));
739 lock.unlockWrite(s);
740 }
741
742 /**
743 * tryOptimisticRead stamp does not validate if a write lock
744 * intervenes in another thread
745 */
746 public void testValidateOptimisticWriteLocked2()
747 throws InterruptedException {
748 final CountDownLatch locked = new CountDownLatch(1);
749 final StampedLock lock = new StampedLock();
750 final long p = assertValid(lock, lock.tryOptimisticRead());
751
752 Thread t = newStartedThread(new CheckedInterruptedRunnable() {
753 public void realRun() throws InterruptedException {
754 lock.writeLockInterruptibly();
755 locked.countDown();
756 lock.writeLockInterruptibly();
757 }});
758
759 await(locked);
760 assertFalse(lock.validate(p));
761 assertEquals(0L, lock.tryOptimisticRead());
762 assertThreadBlocks(t, Thread.State.WAITING);
763 t.interrupt();
764 awaitTermination(t);
765 assertTrue(lock.isWriteLocked());
766 }
767
768 /**
769 * tryConvertToOptimisticRead succeeds and validates if successfully locked
770 */
771 public void testTryConvertToOptimisticRead() throws InterruptedException {
772 StampedLock lock = new StampedLock();
773 long s, p, q;
774 assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
775
776 s = assertValid(lock, lock.tryOptimisticRead());
777 assertEquals(s, lock.tryConvertToOptimisticRead(s));
778 assertTrue(lock.validate(s));
779
780 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
781 s = assertValid(lock, writeLocker.apply(lock));
782 p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
783 assertFalse(lock.validate(s));
784 assertTrue(lock.validate(p));
785 assertUnlocked(lock);
786 }
787
788 for (Function<StampedLock, Long> readLocker : readLockers()) {
789 s = assertValid(lock, readLocker.apply(lock));
790 q = assertValid(lock, lock.tryOptimisticRead());
791 assertEquals(q, lock.tryConvertToOptimisticRead(q));
792 assertTrue(lock.validate(q));
793 assertTrue(lock.isReadLocked());
794 p = assertValid(lock, lock.tryConvertToOptimisticRead(s));
795 assertTrue(lock.validate(p));
796 assertTrue(lock.validate(s));
797 assertUnlocked(lock);
798 assertEquals(q, lock.tryConvertToOptimisticRead(q));
799 assertTrue(lock.validate(q));
800 }
801 }
802
803 /**
804 * tryConvertToReadLock succeeds for valid stamps
805 */
806 public void testTryConvertToReadLock() throws InterruptedException {
807 StampedLock lock = new StampedLock();
808 long s, p;
809
810 assertEquals(0L, lock.tryConvertToReadLock(0L));
811
812 s = assertValid(lock, lock.tryOptimisticRead());
813 p = assertValid(lock, lock.tryConvertToReadLock(s));
814 assertTrue(lock.isReadLocked());
815 assertEquals(1, lock.getReadLockCount());
816 assertTrue(lock.validate(s));
817 lock.unlockRead(p);
818
819 s = assertValid(lock, lock.tryOptimisticRead());
820 lock.readLock();
821 p = assertValid(lock, lock.tryConvertToReadLock(s));
822 assertTrue(lock.isReadLocked());
823 assertEquals(2, lock.getReadLockCount());
824 lock.unlockRead(p);
825 lock.unlockRead(p);
826 assertUnlocked(lock);
827
828 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
829 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
830 s = assertValid(lock, writeLocker.apply(lock));
831 p = assertValid(lock, lock.tryConvertToReadLock(s));
832 assertFalse(lock.validate(s));
833 assertTrue(lock.isReadLocked());
834 assertEquals(1, lock.getReadLockCount());
835 readUnlocker.accept(lock, p);
836 }
837
838 for (Function<StampedLock, Long> readLocker : readLockers()) {
839 s = assertValid(lock, readLocker.apply(lock));
840 assertEquals(s, lock.tryConvertToReadLock(s));
841 assertTrue(lock.validate(s));
842 assertTrue(lock.isReadLocked());
843 assertEquals(1, lock.getReadLockCount());
844 readUnlocker.accept(lock, s);
845 }
846 }
847 }
848
849 /**
850 * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked
851 */
852 public void testTryConvertToWriteLock() throws InterruptedException {
853 StampedLock lock = new StampedLock();
854 long s, p;
855
856 assertEquals(0L, lock.tryConvertToWriteLock(0L));
857
858 assertTrue((s = lock.tryOptimisticRead()) != 0L);
859 assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
860 assertTrue(lock.isWriteLocked());
861 lock.unlockWrite(p);
862
863 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
864 for (Function<StampedLock, Long> writeLocker : writeLockers()) {
865 s = assertValid(lock, writeLocker.apply(lock));
866 assertEquals(s, lock.tryConvertToWriteLock(s));
867 assertTrue(lock.validate(s));
868 assertTrue(lock.isWriteLocked());
869 writeUnlocker.accept(lock, s);
870 }
871
872 for (Function<StampedLock, Long> readLocker : readLockers()) {
873 s = assertValid(lock, readLocker.apply(lock));
874 p = assertValid(lock, lock.tryConvertToWriteLock(s));
875 assertFalse(lock.validate(s));
876 assertTrue(lock.validate(p));
877 assertTrue(lock.isWriteLocked());
878 writeUnlocker.accept(lock, p);
879 }
880 }
881
882 // failure if multiply read locked
883 for (Function<StampedLock, Long> readLocker : readLockers()) {
884 s = assertValid(lock, readLocker.apply(lock));
885 p = assertValid(lock, readLocker.apply(lock));
886 assertEquals(0L, lock.tryConvertToWriteLock(s));
887 assertTrue(lock.validate(s));
888 assertTrue(lock.validate(p));
889 assertEquals(2, lock.getReadLockCount());
890 lock.unlock(p);
891 lock.unlock(s);
892 assertUnlocked(lock);
893 }
894 }
895
896 /**
897 * asWriteLock can be locked and unlocked
898 */
899 public void testAsWriteLock() throws Throwable {
900 StampedLock sl = new StampedLock();
901 Lock lock = sl.asWriteLock();
902 for (Action locker : lockLockers(lock)) {
903 locker.run();
904 assertTrue(sl.isWriteLocked());
905 assertFalse(sl.isReadLocked());
906 assertFalse(lock.tryLock());
907 lock.unlock();
908 assertUnlocked(sl);
909 }
910 }
911
912 /**
913 * asReadLock can be locked and unlocked
914 */
915 public void testAsReadLock() throws Throwable {
916 StampedLock sl = new StampedLock();
917 Lock lock = sl.asReadLock();
918 for (Action locker : lockLockers(lock)) {
919 locker.run();
920 assertTrue(sl.isReadLocked());
921 assertFalse(sl.isWriteLocked());
922 assertEquals(1, sl.getReadLockCount());
923 locker.run();
924 assertTrue(sl.isReadLocked());
925 assertEquals(2, sl.getReadLockCount());
926 lock.unlock();
927 lock.unlock();
928 assertUnlocked(sl);
929 }
930 }
931
932 /**
933 * asReadWriteLock.writeLock can be locked and unlocked
934 */
935 public void testAsReadWriteLockWriteLock() throws Throwable {
936 StampedLock sl = new StampedLock();
937 Lock lock = sl.asReadWriteLock().writeLock();
938 for (Action locker : lockLockers(lock)) {
939 locker.run();
940 assertTrue(sl.isWriteLocked());
941 assertFalse(sl.isReadLocked());
942 assertFalse(lock.tryLock());
943 lock.unlock();
944 assertUnlocked(sl);
945 }
946 }
947
948 /**
949 * asReadWriteLock.readLock can be locked and unlocked
950 */
951 public void testAsReadWriteLockReadLock() throws Throwable {
952 StampedLock sl = new StampedLock();
953 Lock lock = sl.asReadWriteLock().readLock();
954 for (Action locker : lockLockers(lock)) {
955 locker.run();
956 assertTrue(sl.isReadLocked());
957 assertFalse(sl.isWriteLocked());
958 assertEquals(1, sl.getReadLockCount());
959 locker.run();
960 assertTrue(sl.isReadLocked());
961 assertEquals(2, sl.getReadLockCount());
962 lock.unlock();
963 lock.unlock();
964 assertUnlocked(sl);
965 }
966 }
967
968 /**
969 * Lock.newCondition throws UnsupportedOperationException
970 */
971 public void testLockViewsDoNotSupportConditions() {
972 StampedLock sl = new StampedLock();
973 assertThrows(UnsupportedOperationException.class,
974 () -> sl.asWriteLock().newCondition(),
975 () -> sl.asReadLock().newCondition(),
976 () -> sl.asReadWriteLock().writeLock().newCondition(),
977 () -> sl.asReadWriteLock().readLock().newCondition());
978 }
979
980 /**
981 * Passing optimistic read stamps to unlock operations result in
982 * IllegalMonitorStateException
983 */
984 public void testCannotUnlockOptimisticReadStamps() {
985 Runnable[] actions = {
986 () -> {
987 StampedLock sl = new StampedLock();
988 long stamp = assertValid(sl, sl.tryOptimisticRead());
989 sl.unlockRead(stamp);
990 },
991 () -> {
992 StampedLock sl = new StampedLock();
993 long stamp = sl.tryOptimisticRead();
994 sl.unlock(stamp);
995 },
996
997 () -> {
998 StampedLock sl = new StampedLock();
999 long stamp = sl.tryOptimisticRead();
1000 sl.writeLock();
1001 sl.unlock(stamp);
1002 },
1003 () -> {
1004 StampedLock sl = new StampedLock();
1005 sl.readLock();
1006 long stamp = assertValid(sl, sl.tryOptimisticRead());
1007 sl.unlockRead(stamp);
1008 },
1009 () -> {
1010 StampedLock sl = new StampedLock();
1011 sl.readLock();
1012 long stamp = assertValid(sl, sl.tryOptimisticRead());
1013 sl.unlock(stamp);
1014 },
1015
1016 () -> {
1017 StampedLock sl = new StampedLock();
1018 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1019 assertValid(sl, stamp);
1020 sl.writeLock();
1021 sl.unlockWrite(stamp);
1022 },
1023 () -> {
1024 StampedLock sl = new StampedLock();
1025 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1026 sl.writeLock();
1027 sl.unlock(stamp);
1028 },
1029 () -> {
1030 StampedLock sl = new StampedLock();
1031 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1032 sl.readLock();
1033 sl.unlockRead(stamp);
1034 },
1035 () -> {
1036 StampedLock sl = new StampedLock();
1037 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
1038 sl.readLock();
1039 sl.unlock(stamp);
1040 },
1041
1042 () -> {
1043 StampedLock sl = new StampedLock();
1044 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1045 assertValid(sl, stamp);
1046 sl.writeLock();
1047 sl.unlockWrite(stamp);
1048 },
1049 () -> {
1050 StampedLock sl = new StampedLock();
1051 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1052 sl.writeLock();
1053 sl.unlock(stamp);
1054 },
1055 () -> {
1056 StampedLock sl = new StampedLock();
1057 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1058 sl.readLock();
1059 sl.unlockRead(stamp);
1060 },
1061 () -> {
1062 StampedLock sl = new StampedLock();
1063 sl.readLock();
1064 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1065 assertValid(sl, stamp);
1066 sl.readLock();
1067 sl.unlockRead(stamp);
1068 },
1069 () -> {
1070 StampedLock sl = new StampedLock();
1071 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1072 sl.readLock();
1073 sl.unlock(stamp);
1074 },
1075 () -> {
1076 StampedLock sl = new StampedLock();
1077 sl.readLock();
1078 long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
1079 sl.readLock();
1080 sl.unlock(stamp);
1081 },
1082 };
1083
1084 assertThrows(IllegalMonitorStateException.class, actions);
1085 }
1086
1087 static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
1088 try { return sl.writeLockInterruptibly(); }
1089 catch (InterruptedException ex) { throw new AssertionError(ex); }
1090 }
1091
1092 static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1093 try { return sl.tryWriteLock(time, unit); }
1094 catch (InterruptedException ex) { throw new AssertionError(ex); }
1095 }
1096
1097 static long readLockInterruptiblyUninterrupted(StampedLock sl) {
1098 try { return sl.readLockInterruptibly(); }
1099 catch (InterruptedException ex) { throw new AssertionError(ex); }
1100 }
1101
1102 static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
1103 try { return sl.tryReadLock(time, unit); }
1104 catch (InterruptedException ex) { throw new AssertionError(ex); }
1105 }
1106
1107 /**
1108 * Invalid stamps result in IllegalMonitorStateException
1109 */
1110 public void testInvalidStampsThrowIllegalMonitorStateException() {
1111 final StampedLock sl = new StampedLock();
1112
1113 assertThrows(IllegalMonitorStateException.class,
1114 () -> sl.unlockWrite(0L),
1115 () -> sl.unlockRead(0L),
1116 () -> sl.unlock(0L));
1117
1118 final long optimisticStamp = sl.tryOptimisticRead();
1119 final long readStamp = sl.readLock();
1120 sl.unlockRead(readStamp);
1121 final long writeStamp = sl.writeLock();
1122 sl.unlockWrite(writeStamp);
1123 assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L);
1124 final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp };
1125 final Runnable assertNoLongerValidStampsThrow = () -> {
1126 for (long noLongerValidStamp : noLongerValidStamps)
1127 assertThrows(IllegalMonitorStateException.class,
1128 () -> sl.unlockWrite(noLongerValidStamp),
1129 () -> sl.unlockRead(noLongerValidStamp),
1130 () -> sl.unlock(noLongerValidStamp));
1131 };
1132 assertNoLongerValidStampsThrow.run();
1133
1134 for (Function<StampedLock, Long> readLocker : readLockers())
1135 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) {
1136 final long stamp = readLocker.apply(sl);
1137 assertValid(sl, stamp);
1138 assertNoLongerValidStampsThrow.run();
1139 assertThrows(IllegalMonitorStateException.class,
1140 () -> sl.unlockWrite(stamp),
1141 () -> sl.unlockRead(sl.tryOptimisticRead()),
1142 () -> sl.unlockRead(0L));
1143 readUnlocker.accept(sl, stamp);
1144 assertUnlocked(sl);
1145 assertNoLongerValidStampsThrow.run();
1146 }
1147
1148 for (Function<StampedLock, Long> writeLocker : writeLockers())
1149 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1150 final long stamp = writeLocker.apply(sl);
1151 assertValid(sl, stamp);
1152 assertNoLongerValidStampsThrow.run();
1153 assertThrows(IllegalMonitorStateException.class,
1154 () -> sl.unlockRead(stamp),
1155 () -> sl.unlockWrite(0L));
1156 writeUnlocker.accept(sl, stamp);
1157 assertUnlocked(sl);
1158 assertNoLongerValidStampsThrow.run();
1159 }
1160 }
1161
1162 /**
1163 * Read locks can be very deeply nested
1164 */
1165 public void testDeeplyNestedReadLocks() {
1166 final StampedLock lock = new StampedLock();
1167 final int depth = 300;
1168 final long[] stamps = new long[depth];
1169 final List<Function<StampedLock, Long>> readLockers = readLockers();
1170 final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers();
1171 for (int i = 0; i < depth; i++) {
1172 Function<StampedLock, Long> readLocker
1173 = readLockers.get(i % readLockers.size());
1174 long stamp = readLocker.apply(lock);
1175 assertEquals(i + 1, lock.getReadLockCount());
1176 assertTrue(lock.isReadLocked());
1177 stamps[i] = stamp;
1178 }
1179 for (int i = 0; i < depth; i++) {
1180 BiConsumer<StampedLock, Long> readUnlocker
1181 = readUnlockers.get(i % readUnlockers.size());
1182 assertEquals(depth - i, lock.getReadLockCount());
1183 assertTrue(lock.isReadLocked());
1184 readUnlocker.accept(lock, stamps[depth - 1 - i]);
1185 }
1186 assertUnlocked(lock);
1187 }
1188
1189 /**
1190 * Stamped locks are not reentrant.
1191 */
1192 public void testNonReentrant() throws InterruptedException {
1193 final StampedLock lock = new StampedLock();
1194 long stamp;
1195
1196 stamp = lock.writeLock();
1197 assertValid(lock, stamp);
1198 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1199 assertEquals(0L, lock.tryReadLock(0L, DAYS));
1200 assertValid(lock, stamp);
1201 lock.unlockWrite(stamp);
1202
1203 stamp = lock.tryWriteLock(1L, DAYS);
1204 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1205 assertValid(lock, stamp);
1206 lock.unlockWrite(stamp);
1207
1208 stamp = lock.readLock();
1209 assertEquals(0L, lock.tryWriteLock(0L, DAYS));
1210 assertValid(lock, stamp);
1211 lock.unlockRead(stamp);
1212 }
1213
1214 /**
1215 * """StampedLocks have no notion of ownership. Locks acquired in
1216 * one thread can be released or converted in another."""
1217 */
1218 public void testNoOwnership() throws Throwable {
1219 ArrayList<Future<?>> futures = new ArrayList<>();
1220 for (Function<StampedLock, Long> writeLocker : writeLockers())
1221 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
1222 StampedLock lock = new StampedLock();
1223 long stamp = writeLocker.apply(lock);
1224 futures.add(cachedThreadPool.submit(new CheckedRunnable() {
1225 public void realRun() {
1226 writeUnlocker.accept(lock, stamp);
1227 assertUnlocked(lock);
1228 assertFalse(lock.validate(stamp));
1229 }}));
1230 }
1231 for (Future<?> future : futures)
1232 assertNull(future.get());
1233 }
1234
1235 /** Tries out sample usage code from StampedLock javadoc. */
1236 public void testSampleUsage() throws Throwable {
1237 class Point {
1238 private double x, y;
1239 private final StampedLock sl = new StampedLock();
1240
1241 void move(double deltaX, double deltaY) { // an exclusively locked method
1242 long stamp = sl.writeLock();
1243 try {
1244 x += deltaX;
1245 y += deltaY;
1246 } finally {
1247 sl.unlockWrite(stamp);
1248 }
1249 }
1250
1251 double distanceFromOrigin() { // A read-only method
1252 double currentX, currentY;
1253 long stamp = sl.tryOptimisticRead();
1254 do {
1255 if (stamp == 0L)
1256 stamp = sl.readLock();
1257 try {
1258 // possibly racy reads
1259 currentX = x;
1260 currentY = y;
1261 } finally {
1262 stamp = sl.tryConvertToOptimisticRead(stamp);
1263 }
1264 } while (stamp == 0);
1265 return Math.hypot(currentX, currentY);
1266 }
1267
1268 double distanceFromOrigin2() {
1269 long stamp = sl.tryOptimisticRead();
1270 try {
1271 retryHoldingLock:
1272 for (;; stamp = sl.readLock()) {
1273 if (stamp == 0L)
1274 continue retryHoldingLock;
1275 // possibly racy reads
1276 double currentX = x;
1277 double currentY = y;
1278 if (!sl.validate(stamp))
1279 continue retryHoldingLock;
1280 return Math.hypot(currentX, currentY);
1281 }
1282 } finally {
1283 if (StampedLock.isReadLockStamp(stamp))
1284 sl.unlockRead(stamp);
1285 }
1286 }
1287
1288 void moveIfAtOrigin(double newX, double newY) {
1289 long stamp = sl.readLock();
1290 try {
1291 while (x == 0.0 && y == 0.0) {
1292 long ws = sl.tryConvertToWriteLock(stamp);
1293 if (ws != 0L) {
1294 stamp = ws;
1295 x = newX;
1296 y = newY;
1297 return;
1298 }
1299 else {
1300 sl.unlockRead(stamp);
1301 stamp = sl.writeLock();
1302 }
1303 }
1304 } finally {
1305 sl.unlock(stamp);
1306 }
1307 }
1308 }
1309
1310 Point p = new Point();
1311 p.move(3.0, 4.0);
1312 assertEquals(5.0, p.distanceFromOrigin());
1313 p.moveIfAtOrigin(5.0, 12.0);
1314 assertEquals(5.0, p.distanceFromOrigin2());
1315 }
1316
1317 /**
1318 * Stamp inspection methods work as expected, and do not inspect
1319 * the state of the lock itself.
1320 */
1321 public void testStampStateInspectionMethods() {
1322 StampedLock lock = new StampedLock();
1323
1324 assertFalse(isWriteLockStamp(0L));
1325 assertFalse(isReadLockStamp(0L));
1326 assertFalse(isLockStamp(0L));
1327 assertFalse(isOptimisticReadStamp(0L));
1328
1329 {
1330 long stamp = lock.writeLock();
1331 for (int i = 0; i < 2; i++) {
1332 assertTrue(isWriteLockStamp(stamp));
1333 assertFalse(isReadLockStamp(stamp));
1334 assertTrue(isLockStamp(stamp));
1335 assertFalse(isOptimisticReadStamp(stamp));
1336 if (i == 0)
1337 lock.unlockWrite(stamp);
1338 }
1339 }
1340
1341 {
1342 long stamp = lock.readLock();
1343 for (int i = 0; i < 2; i++) {
1344 assertFalse(isWriteLockStamp(stamp));
1345 assertTrue(isReadLockStamp(stamp));
1346 assertTrue(isLockStamp(stamp));
1347 assertFalse(isOptimisticReadStamp(stamp));
1348 if (i == 0)
1349 lock.unlockRead(stamp);
1350 }
1351 }
1352
1353 {
1354 long optimisticStamp = lock.tryOptimisticRead();
1355 long readStamp = lock.tryConvertToReadLock(optimisticStamp);
1356 long writeStamp = lock.tryConvertToWriteLock(readStamp);
1357 for (int i = 0; i < 2; i++) {
1358 assertFalse(isWriteLockStamp(optimisticStamp));
1359 assertFalse(isReadLockStamp(optimisticStamp));
1360 assertFalse(isLockStamp(optimisticStamp));
1361 assertTrue(isOptimisticReadStamp(optimisticStamp));
1362
1363 assertFalse(isWriteLockStamp(readStamp));
1364 assertTrue(isReadLockStamp(readStamp));
1365 assertTrue(isLockStamp(readStamp));
1366 assertFalse(isOptimisticReadStamp(readStamp));
1367
1368 assertTrue(isWriteLockStamp(writeStamp));
1369 assertFalse(isReadLockStamp(writeStamp));
1370 assertTrue(isLockStamp(writeStamp));
1371 assertFalse(isOptimisticReadStamp(writeStamp));
1372 if (i == 0)
1373 lock.unlockWrite(writeStamp);
1374 }
1375 }
1376 }
1377
1378 }