ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/StampedLockTest.java
Revision: 1.33
Committed: Sat Feb 18 14:32:09 2017 UTC (7 years, 2 months ago) by jsr166
Branch: MAIN
Changes since 1.32: +25 -19 lines
Log Message:
various minor improvements

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