1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23 /* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Doug Lea and Martin Buchholz 30 * with assistance from members of JCP JSR-166 Expert Group and 31 * released to the public domain, as explained at 32 * http://creativecommons.org/publicdomain/zero/1.0/ 33 */ 34 35 import static java.util.concurrent.TimeUnit.DAYS; 36 import static java.util.concurrent.TimeUnit.MILLISECONDS; 37 38 import static java.util.concurrent.locks.StampedLock.isLockStamp; 39 import static java.util.concurrent.locks.StampedLock.isOptimisticReadStamp; 40 import static java.util.concurrent.locks.StampedLock.isReadLockStamp; 41 import static java.util.concurrent.locks.StampedLock.isWriteLockStamp; 42 43 import java.util.ArrayList; 44 import java.util.List; 45 import java.util.concurrent.Callable; 46 import java.util.concurrent.CompletableFuture; 47 import java.util.concurrent.CountDownLatch; 48 import java.util.concurrent.Future; 49 import java.util.concurrent.ThreadLocalRandom; 50 import java.util.concurrent.TimeUnit; 51 import java.util.concurrent.atomic.AtomicBoolean; 52 import java.util.concurrent.locks.Lock; 53 import java.util.concurrent.locks.StampedLock; 54 import java.util.function.BiConsumer; 55 import java.util.function.Consumer; 56 import java.util.function.Function; 57 58 import junit.framework.Test; 59 import junit.framework.TestSuite; 60 61 public class StampedLockTest extends JSR166TestCase { 62 public static void main(String[] args) { 63 main(suite(), args); 64 } 65 public static Test suite() { 66 return new TestSuite(StampedLockTest.class); 67 } 68 69 /** 70 * Releases write lock, checking isWriteLocked before and after 71 */ 72 void releaseWriteLock(StampedLock lock, long stamp) { 73 assertTrue(lock.isWriteLocked()); 74 assertValid(lock, stamp); 75 lock.unlockWrite(stamp); 76 assertFalse(lock.isWriteLocked()); 77 assertFalse(lock.validate(stamp)); 78 } 79 80 /** 81 * Releases read lock, checking isReadLocked before and after 82 */ 83 void releaseReadLock(StampedLock lock, long stamp) { 84 assertTrue(lock.isReadLocked()); 85 assertValid(lock, stamp); 86 lock.unlockRead(stamp); 87 assertFalse(lock.isReadLocked()); 88 assertTrue(lock.validate(stamp)); 89 } 90 91 long assertNonZero(long v) { 92 assertTrue(v != 0L); 93 return v; 94 } 95 96 long assertValid(StampedLock lock, long stamp) { 97 assertTrue(stamp != 0L); 98 assertTrue(lock.validate(stamp)); 99 return stamp; 100 } 101 102 void assertUnlocked(StampedLock lock) { 103 assertFalse(lock.isReadLocked()); 104 assertFalse(lock.isWriteLocked()); 105 assertEquals(0, lock.getReadLockCount()); 106 assertValid(lock, lock.tryOptimisticRead()); 107 } 108 109 List<Action> lockLockers(Lock lock) { 110 return List.of( 111 () -> lock.lock(), 112 () -> lock.lockInterruptibly(), 113 () -> lock.tryLock(), 114 () -> lock.tryLock(Long.MIN_VALUE, DAYS), 115 () -> lock.tryLock(0L, DAYS), 116 () -> lock.tryLock(Long.MAX_VALUE, DAYS)); 117 } 118 119 List<Function<StampedLock, Long>> readLockers() { 120 return List.of( 121 sl -> sl.readLock(), 122 sl -> sl.tryReadLock(), 123 sl -> readLockInterruptiblyUninterrupted(sl), 124 sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS), 125 sl -> tryReadLockUninterrupted(sl, 0L, DAYS), 126 sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead())); 127 } 128 129 List<BiConsumer<StampedLock, Long>> readUnlockers() { 130 return List.of( 131 (sl, stamp) -> sl.unlockRead(stamp), 132 (sl, stamp) -> assertTrue(sl.tryUnlockRead()), 133 (sl, stamp) -> sl.asReadLock().unlock(), 134 (sl, stamp) -> sl.unlock(stamp), 135 (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp))); 136 } 137 138 List<Function<StampedLock, Long>> writeLockers() { 139 return List.of( 140 sl -> sl.writeLock(), 141 sl -> sl.tryWriteLock(), 142 sl -> writeLockInterruptiblyUninterrupted(sl), 143 sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS), 144 sl -> tryWriteLockUninterrupted(sl, 0L, DAYS), 145 sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead())); 146 } 147 148 List<BiConsumer<StampedLock, Long>> writeUnlockers() { 149 return List.of( 150 (sl, stamp) -> sl.unlockWrite(stamp), 151 (sl, stamp) -> assertTrue(sl.tryUnlockWrite()), 152 (sl, stamp) -> sl.asWriteLock().unlock(), 153 (sl, stamp) -> sl.unlock(stamp), 154 (sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp))); 155 } 156 157 /** 158 * Constructed StampedLock is in unlocked state 159 */ 160 public void testConstructor() { 161 assertUnlocked(new StampedLock()); 162 } 163 164 /** 165 * write-locking, then unlocking, an unlocked lock succeed 166 */ 167 public void testWriteLock_lockUnlock() { 168 StampedLock lock = new StampedLock(); 169 170 for (Function<StampedLock, Long> writeLocker : writeLockers()) 171 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 172 assertFalse(lock.isWriteLocked()); 173 assertFalse(lock.isReadLocked()); 174 assertEquals(0, lock.getReadLockCount()); 175 176 long s = writeLocker.apply(lock); 177 assertValid(lock, s); 178 assertTrue(lock.isWriteLocked()); 179 assertFalse(lock.isReadLocked()); 180 assertEquals(0, lock.getReadLockCount()); 181 writeUnlocker.accept(lock, s); 182 assertUnlocked(lock); 183 } 184 } 185 186 /** 187 * read-locking, then unlocking, an unlocked lock succeed 188 */ 189 public void testReadLock_lockUnlock() { 190 StampedLock lock = new StampedLock(); 191 192 for (Function<StampedLock, Long> readLocker : readLockers()) 193 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 194 long s = 42; 195 for (int i = 0; i < 2; i++) { 196 s = assertValid(lock, readLocker.apply(lock)); 197 assertFalse(lock.isWriteLocked()); 198 assertTrue(lock.isReadLocked()); 199 assertEquals(i + 1, lock.getReadLockCount()); 200 } 201 for (int i = 0; i < 2; i++) { 202 assertFalse(lock.isWriteLocked()); 203 assertTrue(lock.isReadLocked()); 204 assertEquals(2 - i, lock.getReadLockCount()); 205 readUnlocker.accept(lock, s); 206 } 207 assertUnlocked(lock); 208 } 209 } 210 211 /** 212 * tryUnlockWrite fails if not write locked 213 */ 214 public void testTryUnlockWrite_failure() { 215 StampedLock lock = new StampedLock(); 216 assertFalse(lock.tryUnlockWrite()); 217 218 for (Function<StampedLock, Long> readLocker : readLockers()) 219 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 220 long s = assertValid(lock, readLocker.apply(lock)); 221 assertFalse(lock.tryUnlockWrite()); 222 assertTrue(lock.isReadLocked()); 223 readUnlocker.accept(lock, s); 224 assertUnlocked(lock); 225 } 226 } 227 228 /** 229 * tryUnlockRead fails if not read locked 230 */ 231 public void testTryUnlockRead_failure() { 232 StampedLock lock = new StampedLock(); 233 assertFalse(lock.tryUnlockRead()); 234 235 for (Function<StampedLock, Long> writeLocker : writeLockers()) 236 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 237 long s = writeLocker.apply(lock); 238 assertFalse(lock.tryUnlockRead()); 239 assertTrue(lock.isWriteLocked()); 240 writeUnlocker.accept(lock, s); 241 assertUnlocked(lock); 242 } 243 } 244 245 /** 246 * validate(0L) fails 247 */ 248 public void testValidate0() { 249 StampedLock lock = new StampedLock(); 250 assertFalse(lock.validate(0L)); 251 } 252 253 /** 254 * A stamp obtained from a successful lock operation validates while the lock is held 255 */ 256 public void testValidate() throws InterruptedException { 257 StampedLock lock = new StampedLock(); 258 259 for (Function<StampedLock, Long> readLocker : readLockers()) 260 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 261 long s = assertNonZero(readLocker.apply(lock)); 262 assertTrue(lock.validate(s)); 263 readUnlocker.accept(lock, s); 264 } 265 266 for (Function<StampedLock, Long> writeLocker : writeLockers()) 267 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 268 long s = assertNonZero(writeLocker.apply(lock)); 269 assertTrue(lock.validate(s)); 270 writeUnlocker.accept(lock, s); 271 } 272 } 273 274 /** 275 * A stamp obtained from an unsuccessful lock operation does not validate 276 */ 277 public void testValidate2() throws InterruptedException { 278 StampedLock lock = new StampedLock(); 279 long s = assertNonZero(lock.writeLock()); 280 assertTrue(lock.validate(s)); 281 assertFalse(lock.validate(lock.tryWriteLock())); 282 assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(), 283 randomTimeUnit()))); 284 assertFalse(lock.validate(lock.tryReadLock())); 285 assertFalse(lock.validate(lock.tryWriteLock(randomExpiredTimeout(), 286 randomTimeUnit()))); 287 assertFalse(lock.validate(lock.tryOptimisticRead())); 288 lock.unlockWrite(s); 289 } 290 291 void assertThrowInterruptedExceptionWhenPreInterrupted(Action[] actions) { 292 for (Action action : actions) { 293 Thread.currentThread().interrupt(); 294 try { 295 action.run(); 296 shouldThrow(); 297 } 298 catch (InterruptedException success) {} 299 catch (Throwable fail) { threadUnexpectedException(fail); } 300 assertFalse(Thread.interrupted()); 301 } 302 } 303 304 /** 305 * interruptible operations throw InterruptedException when pre-interrupted 306 */ 307 public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() { 308 final StampedLock lock = new StampedLock(); 309 310 Action[] interruptibleLockActions = { 311 () -> lock.writeLockInterruptibly(), 312 () -> lock.tryWriteLock(Long.MIN_VALUE, DAYS), 313 () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS), 314 () -> lock.readLockInterruptibly(), 315 () -> lock.tryReadLock(Long.MIN_VALUE, DAYS), 316 () -> lock.tryReadLock(Long.MAX_VALUE, DAYS), 317 () -> lock.asWriteLock().lockInterruptibly(), 318 () -> lock.asWriteLock().tryLock(0L, DAYS), 319 () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS), 320 () -> lock.asReadLock().lockInterruptibly(), 321 () -> lock.asReadLock().tryLock(0L, DAYS), 322 () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS), 323 }; 324 shuffle(interruptibleLockActions); 325 326 assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions); 327 { 328 long s = lock.writeLock(); 329 assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions); 330 lock.unlockWrite(s); 331 } 332 { 333 long s = lock.readLock(); 334 assertThrowInterruptedExceptionWhenPreInterrupted(interruptibleLockActions); 335 lock.unlockRead(s); 336 } 337 } 338 339 void assertThrowInterruptedExceptionWhenInterrupted(Action[] actions) { 340 int n = actions.length; 341 Future<?>[] futures = new Future<?>[n]; 342 CountDownLatch threadsStarted = new CountDownLatch(n); 343 CountDownLatch done = new CountDownLatch(n); 344 345 for (int i = 0; i < n; i++) { 346 Action action = actions[i]; 347 futures[i] = cachedThreadPool.submit(new CheckedRunnable() { 348 public void realRun() throws Throwable { 349 threadsStarted.countDown(); 350 try { 351 action.run(); 352 shouldThrow(); 353 } 354 catch (InterruptedException success) {} 355 catch (Throwable fail) { threadUnexpectedException(fail); } 356 assertFalse(Thread.interrupted()); 357 done.countDown(); 358 }}); 359 } 360 361 await(threadsStarted); 362 assertEquals(n, done.getCount()); 363 for (Future<?> future : futures) // Interrupt all the tasks 364 future.cancel(true); 365 await(done); 366 } 367 368 /** 369 * interruptible operations throw InterruptedException when write locked and interrupted 370 */ 371 public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() { 372 final StampedLock lock = new StampedLock(); 373 long stamp = lock.writeLock(); 374 375 Action[] interruptibleLockBlockingActions = { 376 () -> lock.writeLockInterruptibly(), 377 () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS), 378 () -> lock.readLockInterruptibly(), 379 () -> lock.tryReadLock(Long.MAX_VALUE, DAYS), 380 () -> lock.asWriteLock().lockInterruptibly(), 381 () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS), 382 () -> lock.asReadLock().lockInterruptibly(), 383 () -> lock.asReadLock().tryLock(Long.MAX_VALUE, DAYS), 384 }; 385 shuffle(interruptibleLockBlockingActions); 386 387 assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions); 388 389 releaseWriteLock(lock, stamp); 390 } 391 392 /** 393 * interruptible operations throw InterruptedException when read locked and interrupted 394 */ 395 public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() { 396 final StampedLock lock = new StampedLock(); 397 long stamp = lock.readLock(); 398 399 Action[] interruptibleLockBlockingActions = { 400 () -> lock.writeLockInterruptibly(), 401 () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS), 402 () -> lock.asWriteLock().lockInterruptibly(), 403 () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS), 404 }; 405 shuffle(interruptibleLockBlockingActions); 406 407 assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions); 408 409 releaseReadLock(lock, stamp); 410 } 411 412 /** 413 * Non-interruptible operations ignore and preserve interrupt status 414 */ 415 public void testNonInterruptibleOperationsIgnoreInterrupts() { 416 final StampedLock lock = new StampedLock(); 417 Thread.currentThread().interrupt(); 418 419 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 420 long s = assertValid(lock, lock.readLock()); 421 readUnlocker.accept(lock, s); 422 s = assertValid(lock, lock.tryReadLock()); 423 readUnlocker.accept(lock, s); 424 } 425 426 lock.asReadLock().lock(); 427 lock.asReadLock().unlock(); 428 429 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 430 long s = assertValid(lock, lock.writeLock()); 431 writeUnlocker.accept(lock, s); 432 s = assertValid(lock, lock.tryWriteLock()); 433 writeUnlocker.accept(lock, s); 434 } 435 436 lock.asWriteLock().lock(); 437 lock.asWriteLock().unlock(); 438 439 assertTrue(Thread.interrupted()); 440 } 441 442 /** 443 * tryWriteLock on an unlocked lock succeeds 444 */ 445 public void testTryWriteLock() { 446 final StampedLock lock = new StampedLock(); 447 long s = lock.tryWriteLock(); 448 assertTrue(s != 0L); 449 assertTrue(lock.isWriteLocked()); 450 assertEquals(0L, lock.tryWriteLock()); 451 releaseWriteLock(lock, s); 452 } 453 454 /** 455 * tryWriteLock fails if locked 456 */ 457 public void testTryWriteLockWhenLocked() { 458 final StampedLock lock = new StampedLock(); 459 long s = lock.writeLock(); 460 Thread t = newStartedThread(new CheckedRunnable() { 461 public void realRun() { 462 assertEquals(0L, lock.tryWriteLock()); 463 }}); 464 465 assertEquals(0L, lock.tryWriteLock()); 466 awaitTermination(t); 467 releaseWriteLock(lock, s); 468 } 469 470 /** 471 * tryReadLock fails if write-locked 472 */ 473 public void testTryReadLockWhenLocked() { 474 final StampedLock lock = new StampedLock(); 475 long s = lock.writeLock(); 476 Thread t = newStartedThread(new CheckedRunnable() { 477 public void realRun() { 478 assertEquals(0L, lock.tryReadLock()); 479 }}); 480 481 assertEquals(0L, lock.tryReadLock()); 482 awaitTermination(t); 483 releaseWriteLock(lock, s); 484 } 485 486 /** 487 * Multiple threads can hold a read lock when not write-locked 488 */ 489 public void testMultipleReadLocks() { 490 final StampedLock lock = new StampedLock(); 491 final long s = lock.readLock(); 492 Thread t = newStartedThread(new CheckedRunnable() { 493 public void realRun() throws InterruptedException { 494 long s2 = lock.tryReadLock(); 495 assertValid(lock, s2); 496 lock.unlockRead(s2); 497 long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS); 498 assertValid(lock, s3); 499 lock.unlockRead(s3); 500 long s4 = lock.readLock(); 501 assertValid(lock, s4); 502 lock.unlockRead(s4); 503 lock.asReadLock().lock(); 504 lock.asReadLock().unlock(); 505 lock.asReadLock().lockInterruptibly(); 506 lock.asReadLock().unlock(); 507 lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS); 508 lock.asReadLock().unlock(); 509 }}); 510 511 awaitTermination(t); 512 lock.unlockRead(s); 513 } 514 515 /** 516 * writeLock() succeeds only after a reading thread unlocks 517 */ 518 public void testWriteAfterReadLock() throws InterruptedException { 519 final CountDownLatch aboutToLock = new CountDownLatch(1); 520 final StampedLock lock = new StampedLock(); 521 long rs = lock.readLock(); 522 Thread t = newStartedThread(new CheckedRunnable() { 523 public void realRun() { 524 aboutToLock.countDown(); 525 long s = lock.writeLock(); 526 assertTrue(lock.isWriteLocked()); 527 assertFalse(lock.isReadLocked()); 528 lock.unlockWrite(s); 529 }}); 530 531 await(aboutToLock); 532 assertThreadBlocks(t, Thread.State.WAITING); 533 assertFalse(lock.isWriteLocked()); 534 assertTrue(lock.isReadLocked()); 535 lock.unlockRead(rs); 536 awaitTermination(t); 537 assertUnlocked(lock); 538 } 539 540 /** 541 * writeLock() succeeds only after reading threads unlock 542 */ 543 public void testWriteAfterMultipleReadLocks() { 544 final StampedLock lock = new StampedLock(); 545 long s = lock.readLock(); 546 Thread t1 = newStartedThread(new CheckedRunnable() { 547 public void realRun() { 548 long rs = lock.readLock(); 549 lock.unlockRead(rs); 550 }}); 551 552 awaitTermination(t1); 553 554 Thread t2 = newStartedThread(new CheckedRunnable() { 555 public void realRun() { 556 long ws = lock.writeLock(); 557 lock.unlockWrite(ws); 558 }}); 559 560 assertTrue(lock.isReadLocked()); 561 assertFalse(lock.isWriteLocked()); 562 lock.unlockRead(s); 563 awaitTermination(t2); 564 assertUnlocked(lock); 565 } 566 567 /** 568 * readLock() succeed only after a writing thread unlocks 569 */ 570 public void testReadAfterWriteLock() { 571 final StampedLock lock = new StampedLock(); 572 final CountDownLatch threadsStarted = new CountDownLatch(2); 573 final long s = lock.writeLock(); 574 final Runnable acquireReleaseReadLock = new CheckedRunnable() { 575 public void realRun() { 576 threadsStarted.countDown(); 577 long rs = lock.readLock(); 578 assertTrue(lock.isReadLocked()); 579 assertFalse(lock.isWriteLocked()); 580 lock.unlockRead(rs); 581 }}; 582 Thread t1 = newStartedThread(acquireReleaseReadLock); 583 Thread t2 = newStartedThread(acquireReleaseReadLock); 584 585 await(threadsStarted); 586 assertThreadBlocks(t1, Thread.State.WAITING); 587 assertThreadBlocks(t2, Thread.State.WAITING); 588 assertTrue(lock.isWriteLocked()); 589 assertFalse(lock.isReadLocked()); 590 releaseWriteLock(lock, s); 591 awaitTermination(t1); 592 awaitTermination(t2); 593 assertUnlocked(lock); 594 } 595 596 /** 597 * tryReadLock succeeds if read locked but not write locked 598 */ 599 public void testTryLockWhenReadLocked() { 600 final StampedLock lock = new StampedLock(); 601 long s = lock.readLock(); 602 Thread t = newStartedThread(new CheckedRunnable() { 603 public void realRun() { 604 long rs = lock.tryReadLock(); 605 assertValid(lock, rs); 606 lock.unlockRead(rs); 607 }}); 608 609 awaitTermination(t); 610 lock.unlockRead(s); 611 } 612 613 /** 614 * tryWriteLock fails when read locked 615 */ 616 public void testTryWriteLockWhenReadLocked() { 617 final StampedLock lock = new StampedLock(); 618 long s = lock.readLock(); 619 Thread t = newStartedThread(new CheckedRunnable() { 620 public void realRun() { 621 assertEquals(0L, lock.tryWriteLock()); 622 }}); 623 624 awaitTermination(t); 625 lock.unlockRead(s); 626 } 627 628 /** 629 * timed lock operations time out if lock not available 630 */ 631 public void testTimedLock_Timeout() throws Exception { 632 ArrayList<Future<?>> futures = new ArrayList<>(); 633 634 // Write locked 635 final StampedLock lock = new StampedLock(); 636 long stamp = lock.writeLock(); 637 assertEquals(0L, lock.tryReadLock(0L, DAYS)); 638 assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS)); 639 assertFalse(lock.asReadLock().tryLock(0L, DAYS)); 640 assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS)); 641 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 642 assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS)); 643 assertFalse(lock.asWriteLock().tryLock(0L, DAYS)); 644 assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS)); 645 646 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 647 public void realRun() throws InterruptedException { 648 long startTime = System.nanoTime(); 649 assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS)); 650 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 651 }})); 652 653 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 654 public void realRun() throws InterruptedException { 655 long startTime = System.nanoTime(); 656 assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS)); 657 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 658 }})); 659 660 // Read locked 661 final StampedLock lock2 = new StampedLock(); 662 long stamp2 = lock2.readLock(); 663 assertEquals(0L, lock2.tryWriteLock(0L, DAYS)); 664 assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS)); 665 assertFalse(lock2.asWriteLock().tryLock(0L, DAYS)); 666 assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS)); 667 668 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 669 public void realRun() throws InterruptedException { 670 long startTime = System.nanoTime(); 671 assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS)); 672 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 673 }})); 674 675 for (Future<?> future : futures) 676 assertNull(future.get()); 677 678 releaseWriteLock(lock, stamp); 679 releaseReadLock(lock2, stamp2); 680 } 681 682 /** 683 * writeLockInterruptibly succeeds if unlocked 684 */ 685 public void testWriteLockInterruptibly() throws InterruptedException { 686 final StampedLock lock = new StampedLock(); 687 long s = lock.writeLockInterruptibly(); 688 assertTrue(lock.isWriteLocked()); 689 releaseWriteLock(lock, s); 690 } 691 692 /** 693 * readLockInterruptibly succeeds if lock free 694 */ 695 public void testReadLockInterruptibly() throws InterruptedException { 696 final StampedLock lock = new StampedLock(); 697 698 long s = assertValid(lock, lock.readLockInterruptibly()); 699 assertTrue(lock.isReadLocked()); 700 lock.unlockRead(s); 701 702 lock.asReadLock().lockInterruptibly(); 703 assertTrue(lock.isReadLocked()); 704 lock.asReadLock().unlock(); 705 } 706 707 /** 708 * A serialized lock deserializes as unlocked 709 */ 710 public void testSerialization() { 711 StampedLock lock = new StampedLock(); 712 lock.writeLock(); 713 StampedLock clone = serialClone(lock); 714 assertTrue(lock.isWriteLocked()); 715 assertFalse(clone.isWriteLocked()); 716 long s = clone.writeLock(); 717 assertTrue(clone.isWriteLocked()); 718 clone.unlockWrite(s); 719 assertFalse(clone.isWriteLocked()); 720 } 721 722 /** 723 * toString indicates current lock state 724 */ 725 public void testToString() { 726 StampedLock lock = new StampedLock(); 727 assertTrue(lock.toString().contains("Unlocked")); 728 long s = lock.writeLock(); 729 assertTrue(lock.toString().contains("Write-locked")); 730 lock.unlockWrite(s); 731 s = lock.readLock(); 732 assertTrue(lock.toString().contains("Read-locks")); 733 releaseReadLock(lock, s); 734 } 735 736 /** 737 * tryOptimisticRead succeeds and validates if unlocked, fails if 738 * exclusively locked 739 */ 740 public void testValidateOptimistic() throws InterruptedException { 741 StampedLock lock = new StampedLock(); 742 743 assertValid(lock, lock.tryOptimisticRead()); 744 745 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 746 long s = assertValid(lock, writeLocker.apply(lock)); 747 assertEquals(0L, lock.tryOptimisticRead()); 748 releaseWriteLock(lock, s); 749 } 750 751 for (Function<StampedLock, Long> readLocker : readLockers()) { 752 long s = assertValid(lock, readLocker.apply(lock)); 753 long p = assertValid(lock, lock.tryOptimisticRead()); 754 releaseReadLock(lock, s); 755 assertTrue(lock.validate(p)); 756 } 757 758 assertValid(lock, lock.tryOptimisticRead()); 759 } 760 761 /** 762 * tryOptimisticRead stamp does not validate if a write lock intervenes 763 */ 764 public void testValidateOptimisticWriteLocked() { 765 final StampedLock lock = new StampedLock(); 766 final long p = assertValid(lock, lock.tryOptimisticRead()); 767 final long s = assertValid(lock, lock.writeLock()); 768 assertFalse(lock.validate(p)); 769 assertEquals(0L, lock.tryOptimisticRead()); 770 assertTrue(lock.validate(s)); 771 lock.unlockWrite(s); 772 } 773 774 /** 775 * tryOptimisticRead stamp does not validate if a write lock 776 * intervenes in another thread 777 */ 778 public void testValidateOptimisticWriteLocked2() 779 throws InterruptedException { 780 final CountDownLatch locked = new CountDownLatch(1); 781 final StampedLock lock = new StampedLock(); 782 final long p = assertValid(lock, lock.tryOptimisticRead()); 783 784 Thread t = newStartedThread(new CheckedInterruptedRunnable() { 785 public void realRun() throws InterruptedException { 786 lock.writeLockInterruptibly(); 787 locked.countDown(); 788 lock.writeLockInterruptibly(); 789 }}); 790 791 await(locked); 792 assertFalse(lock.validate(p)); 793 assertEquals(0L, lock.tryOptimisticRead()); 794 assertThreadBlocks(t, Thread.State.WAITING); 795 t.interrupt(); 796 awaitTermination(t); 797 assertTrue(lock.isWriteLocked()); 798 } 799 800 /** 801 * tryConvertToOptimisticRead succeeds and validates if successfully locked 802 */ 803 public void testTryConvertToOptimisticRead() throws InterruptedException { 804 StampedLock lock = new StampedLock(); 805 long s, p, q; 806 assertEquals(0L, lock.tryConvertToOptimisticRead(0L)); 807 808 s = assertValid(lock, lock.tryOptimisticRead()); 809 assertEquals(s, lock.tryConvertToOptimisticRead(s)); 810 assertTrue(lock.validate(s)); 811 812 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 813 s = assertValid(lock, writeLocker.apply(lock)); 814 p = assertValid(lock, lock.tryConvertToOptimisticRead(s)); 815 assertFalse(lock.validate(s)); 816 assertTrue(lock.validate(p)); 817 assertUnlocked(lock); 818 } 819 820 for (Function<StampedLock, Long> readLocker : readLockers()) { 821 s = assertValid(lock, readLocker.apply(lock)); 822 q = assertValid(lock, lock.tryOptimisticRead()); 823 assertEquals(q, lock.tryConvertToOptimisticRead(q)); 824 assertTrue(lock.validate(q)); 825 assertTrue(lock.isReadLocked()); 826 p = assertValid(lock, lock.tryConvertToOptimisticRead(s)); 827 assertTrue(lock.validate(p)); 828 assertTrue(lock.validate(s)); 829 assertUnlocked(lock); 830 assertEquals(q, lock.tryConvertToOptimisticRead(q)); 831 assertTrue(lock.validate(q)); 832 } 833 } 834 835 /** 836 * tryConvertToReadLock succeeds for valid stamps 837 */ 838 public void testTryConvertToReadLock() throws InterruptedException { 839 StampedLock lock = new StampedLock(); 840 long s, p; 841 842 assertEquals(0L, lock.tryConvertToReadLock(0L)); 843 844 s = assertValid(lock, lock.tryOptimisticRead()); 845 p = assertValid(lock, lock.tryConvertToReadLock(s)); 846 assertTrue(lock.isReadLocked()); 847 assertEquals(1, lock.getReadLockCount()); 848 assertTrue(lock.validate(s)); 849 lock.unlockRead(p); 850 851 s = assertValid(lock, lock.tryOptimisticRead()); 852 lock.readLock(); 853 p = assertValid(lock, lock.tryConvertToReadLock(s)); 854 assertTrue(lock.isReadLocked()); 855 assertEquals(2, lock.getReadLockCount()); 856 lock.unlockRead(p); 857 lock.unlockRead(p); 858 assertUnlocked(lock); 859 860 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 861 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 862 s = assertValid(lock, writeLocker.apply(lock)); 863 p = assertValid(lock, lock.tryConvertToReadLock(s)); 864 assertFalse(lock.validate(s)); 865 assertTrue(lock.isReadLocked()); 866 assertEquals(1, lock.getReadLockCount()); 867 readUnlocker.accept(lock, p); 868 } 869 870 for (Function<StampedLock, Long> readLocker : readLockers()) { 871 s = assertValid(lock, readLocker.apply(lock)); 872 assertEquals(s, lock.tryConvertToReadLock(s)); 873 assertTrue(lock.validate(s)); 874 assertTrue(lock.isReadLocked()); 875 assertEquals(1, lock.getReadLockCount()); 876 readUnlocker.accept(lock, s); 877 } 878 } 879 } 880 881 /** 882 * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked 883 */ 884 public void testTryConvertToWriteLock() throws InterruptedException { 885 StampedLock lock = new StampedLock(); 886 long s, p; 887 888 assertEquals(0L, lock.tryConvertToWriteLock(0L)); 889 890 assertTrue((s = lock.tryOptimisticRead()) != 0L); 891 assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); 892 assertTrue(lock.isWriteLocked()); 893 lock.unlockWrite(p); 894 895 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 896 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 897 s = assertValid(lock, writeLocker.apply(lock)); 898 assertEquals(s, lock.tryConvertToWriteLock(s)); 899 assertTrue(lock.validate(s)); 900 assertTrue(lock.isWriteLocked()); 901 writeUnlocker.accept(lock, s); 902 } 903 904 for (Function<StampedLock, Long> readLocker : readLockers()) { 905 s = assertValid(lock, readLocker.apply(lock)); 906 p = assertValid(lock, lock.tryConvertToWriteLock(s)); 907 assertFalse(lock.validate(s)); 908 assertTrue(lock.validate(p)); 909 assertTrue(lock.isWriteLocked()); 910 writeUnlocker.accept(lock, p); 911 } 912 } 913 914 // failure if multiply read locked 915 for (Function<StampedLock, Long> readLocker : readLockers()) { 916 s = assertValid(lock, readLocker.apply(lock)); 917 p = assertValid(lock, readLocker.apply(lock)); 918 assertEquals(0L, lock.tryConvertToWriteLock(s)); 919 assertTrue(lock.validate(s)); 920 assertTrue(lock.validate(p)); 921 assertEquals(2, lock.getReadLockCount()); 922 lock.unlock(p); 923 lock.unlock(s); 924 assertUnlocked(lock); 925 } 926 } 927 928 /** 929 * asWriteLock can be locked and unlocked 930 */ 931 public void testAsWriteLock() throws Throwable { 932 StampedLock sl = new StampedLock(); 933 Lock lock = sl.asWriteLock(); 934 for (Action locker : lockLockers(lock)) { 935 locker.run(); 936 assertTrue(sl.isWriteLocked()); 937 assertFalse(sl.isReadLocked()); 938 assertFalse(lock.tryLock()); 939 lock.unlock(); 940 assertUnlocked(sl); 941 } 942 } 943 944 /** 945 * asReadLock can be locked and unlocked 946 */ 947 public void testAsReadLock() throws Throwable { 948 StampedLock sl = new StampedLock(); 949 Lock lock = sl.asReadLock(); 950 for (Action locker : lockLockers(lock)) { 951 locker.run(); 952 assertTrue(sl.isReadLocked()); 953 assertFalse(sl.isWriteLocked()); 954 assertEquals(1, sl.getReadLockCount()); 955 locker.run(); 956 assertTrue(sl.isReadLocked()); 957 assertEquals(2, sl.getReadLockCount()); 958 lock.unlock(); 959 lock.unlock(); 960 assertUnlocked(sl); 961 } 962 } 963 964 /** 965 * asReadWriteLock.writeLock can be locked and unlocked 966 */ 967 public void testAsReadWriteLockWriteLock() throws Throwable { 968 StampedLock sl = new StampedLock(); 969 Lock lock = sl.asReadWriteLock().writeLock(); 970 for (Action locker : lockLockers(lock)) { 971 locker.run(); 972 assertTrue(sl.isWriteLocked()); 973 assertFalse(sl.isReadLocked()); 974 assertFalse(lock.tryLock()); 975 lock.unlock(); 976 assertUnlocked(sl); 977 } 978 } 979 980 /** 981 * asReadWriteLock.readLock can be locked and unlocked 982 */ 983 public void testAsReadWriteLockReadLock() throws Throwable { 984 StampedLock sl = new StampedLock(); 985 Lock lock = sl.asReadWriteLock().readLock(); 986 for (Action locker : lockLockers(lock)) { 987 locker.run(); 988 assertTrue(sl.isReadLocked()); 989 assertFalse(sl.isWriteLocked()); 990 assertEquals(1, sl.getReadLockCount()); 991 locker.run(); 992 assertTrue(sl.isReadLocked()); 993 assertEquals(2, sl.getReadLockCount()); 994 lock.unlock(); 995 lock.unlock(); 996 assertUnlocked(sl); 997 } 998 } 999 1000 /** 1001 * Lock.newCondition throws UnsupportedOperationException 1002 */ 1003 public void testLockViewsDoNotSupportConditions() { 1004 StampedLock sl = new StampedLock(); 1005 assertThrows(UnsupportedOperationException.class, 1006 () -> sl.asWriteLock().newCondition(), 1007 () -> sl.asReadLock().newCondition(), 1008 () -> sl.asReadWriteLock().writeLock().newCondition(), 1009 () -> sl.asReadWriteLock().readLock().newCondition()); 1010 } 1011 1012 /** 1013 * Passing optimistic read stamps to unlock operations result in 1014 * IllegalMonitorStateException 1015 */ 1016 public void testCannotUnlockOptimisticReadStamps() { 1017 { 1018 StampedLock sl = new StampedLock(); 1019 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1020 assertThrows(IllegalMonitorStateException.class, 1021 () -> sl.unlockRead(stamp)); 1022 } 1023 { 1024 StampedLock sl = new StampedLock(); 1025 long stamp = sl.tryOptimisticRead(); 1026 assertThrows(IllegalMonitorStateException.class, 1027 () -> sl.unlock(stamp)); 1028 } 1029 1030 { 1031 StampedLock sl = new StampedLock(); 1032 long stamp = sl.tryOptimisticRead(); 1033 sl.writeLock(); 1034 assertThrows(IllegalMonitorStateException.class, 1035 () -> sl.unlock(stamp)); 1036 } 1037 { 1038 StampedLock sl = new StampedLock(); 1039 sl.readLock(); 1040 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1041 assertThrows(IllegalMonitorStateException.class, 1042 () -> sl.unlockRead(stamp)); 1043 } 1044 { 1045 StampedLock sl = new StampedLock(); 1046 sl.readLock(); 1047 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1048 assertThrows(IllegalMonitorStateException.class, 1049 () -> sl.unlock(stamp)); 1050 } 1051 1052 { 1053 StampedLock sl = new StampedLock(); 1054 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1055 assertValid(sl, stamp); 1056 sl.writeLock(); 1057 assertThrows(IllegalMonitorStateException.class, 1058 () -> sl.unlockWrite(stamp)); 1059 } 1060 { 1061 StampedLock sl = new StampedLock(); 1062 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1063 sl.writeLock(); 1064 assertThrows(IllegalMonitorStateException.class, 1065 () -> sl.unlock(stamp)); 1066 } 1067 { 1068 StampedLock sl = new StampedLock(); 1069 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1070 sl.readLock(); 1071 assertThrows(IllegalMonitorStateException.class, 1072 () -> sl.unlockRead(stamp)); 1073 } 1074 { 1075 StampedLock sl = new StampedLock(); 1076 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1077 sl.readLock(); 1078 assertThrows(IllegalMonitorStateException.class, 1079 () -> sl.unlock(stamp)); 1080 } 1081 1082 { 1083 StampedLock sl = new StampedLock(); 1084 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1085 assertValid(sl, stamp); 1086 sl.writeLock(); 1087 assertThrows(IllegalMonitorStateException.class, 1088 () -> sl.unlockWrite(stamp)); 1089 } 1090 { 1091 StampedLock sl = new StampedLock(); 1092 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1093 sl.writeLock(); 1094 assertThrows(IllegalMonitorStateException.class, 1095 () -> sl.unlock(stamp)); 1096 } 1097 { 1098 StampedLock sl = new StampedLock(); 1099 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1100 sl.readLock(); 1101 assertThrows(IllegalMonitorStateException.class, 1102 () -> sl.unlockRead(stamp)); 1103 } 1104 { 1105 StampedLock sl = new StampedLock(); 1106 sl.readLock(); 1107 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1108 assertValid(sl, stamp); 1109 sl.readLock(); 1110 assertThrows(IllegalMonitorStateException.class, 1111 () -> sl.unlockRead(stamp)); 1112 } 1113 { 1114 StampedLock sl = new StampedLock(); 1115 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1116 sl.readLock(); 1117 assertThrows(IllegalMonitorStateException.class, 1118 () -> sl.unlock(stamp)); 1119 } 1120 { 1121 StampedLock sl = new StampedLock(); 1122 sl.readLock(); 1123 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1124 sl.readLock(); 1125 assertThrows(IllegalMonitorStateException.class, 1126 () -> sl.unlock(stamp)); 1127 } 1128 } 1129 1130 static long writeLockInterruptiblyUninterrupted(StampedLock sl) { 1131 try { return sl.writeLockInterruptibly(); } 1132 catch (InterruptedException ex) { throw new AssertionError(ex); } 1133 } 1134 1135 static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1136 try { return sl.tryWriteLock(time, unit); } 1137 catch (InterruptedException ex) { throw new AssertionError(ex); } 1138 } 1139 1140 static long readLockInterruptiblyUninterrupted(StampedLock sl) { 1141 try { return sl.readLockInterruptibly(); } 1142 catch (InterruptedException ex) { throw new AssertionError(ex); } 1143 } 1144 1145 static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1146 try { return sl.tryReadLock(time, unit); } 1147 catch (InterruptedException ex) { throw new AssertionError(ex); } 1148 } 1149 1150 /** 1151 * Invalid stamps result in IllegalMonitorStateException 1152 */ 1153 public void testInvalidStampsThrowIllegalMonitorStateException() { 1154 final StampedLock sl = new StampedLock(); 1155 1156 assertThrows(IllegalMonitorStateException.class, 1157 () -> sl.unlockWrite(0L), 1158 () -> sl.unlockRead(0L), 1159 () -> sl.unlock(0L)); 1160 1161 final long optimisticStamp = sl.tryOptimisticRead(); 1162 final long readStamp = sl.readLock(); 1163 sl.unlockRead(readStamp); 1164 final long writeStamp = sl.writeLock(); 1165 sl.unlockWrite(writeStamp); 1166 assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L); 1167 final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp }; 1168 final Runnable assertNoLongerValidStampsThrow = () -> { 1169 for (long noLongerValidStamp : noLongerValidStamps) 1170 assertThrows(IllegalMonitorStateException.class, 1171 () -> sl.unlockWrite(noLongerValidStamp), 1172 () -> sl.unlockRead(noLongerValidStamp), 1173 () -> sl.unlock(noLongerValidStamp)); 1174 }; 1175 assertNoLongerValidStampsThrow.run(); 1176 1177 for (Function<StampedLock, Long> readLocker : readLockers()) 1178 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 1179 final long stamp = readLocker.apply(sl); 1180 assertValid(sl, stamp); 1181 assertNoLongerValidStampsThrow.run(); 1182 assertThrows(IllegalMonitorStateException.class, 1183 () -> sl.unlockWrite(stamp), 1184 () -> sl.unlockRead(sl.tryOptimisticRead()), 1185 () -> sl.unlockRead(0L)); 1186 readUnlocker.accept(sl, stamp); 1187 assertUnlocked(sl); 1188 assertNoLongerValidStampsThrow.run(); 1189 } 1190 1191 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1192 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1193 final long stamp = writeLocker.apply(sl); 1194 assertValid(sl, stamp); 1195 assertNoLongerValidStampsThrow.run(); 1196 assertThrows(IllegalMonitorStateException.class, 1197 () -> sl.unlockRead(stamp), 1198 () -> sl.unlockWrite(0L)); 1199 writeUnlocker.accept(sl, stamp); 1200 assertUnlocked(sl); 1201 assertNoLongerValidStampsThrow.run(); 1202 } 1203 } 1204 1205 /** 1206 * Read locks can be very deeply nested 1207 */ 1208 public void testDeeplyNestedReadLocks() { 1209 final StampedLock lock = new StampedLock(); 1210 final int depth = 300; 1211 final long[] stamps = new long[depth]; 1212 final List<Function<StampedLock, Long>> readLockers = readLockers(); 1213 final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers(); 1214 for (int i = 0; i < depth; i++) { 1215 Function<StampedLock, Long> readLocker 1216 = readLockers.get(i % readLockers.size()); 1217 long stamp = readLocker.apply(lock); 1218 assertEquals(i + 1, lock.getReadLockCount()); 1219 assertTrue(lock.isReadLocked()); 1220 stamps[i] = stamp; 1221 } 1222 for (int i = 0; i < depth; i++) { 1223 BiConsumer<StampedLock, Long> readUnlocker 1224 = readUnlockers.get(i % readUnlockers.size()); 1225 assertEquals(depth - i, lock.getReadLockCount()); 1226 assertTrue(lock.isReadLocked()); 1227 readUnlocker.accept(lock, stamps[depth - 1 - i]); 1228 } 1229 assertUnlocked(lock); 1230 } 1231 1232 /** 1233 * Stamped locks are not reentrant. 1234 */ 1235 public void testNonReentrant() throws InterruptedException { 1236 final StampedLock lock = new StampedLock(); 1237 long stamp; 1238 1239 stamp = lock.writeLock(); 1240 assertValid(lock, stamp); 1241 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1242 assertEquals(0L, lock.tryReadLock(0L, DAYS)); 1243 assertValid(lock, stamp); 1244 lock.unlockWrite(stamp); 1245 1246 stamp = lock.tryWriteLock(1L, DAYS); 1247 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1248 assertValid(lock, stamp); 1249 lock.unlockWrite(stamp); 1250 1251 stamp = lock.readLock(); 1252 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1253 assertValid(lock, stamp); 1254 lock.unlockRead(stamp); 1255 } 1256 1257 /** 1258 * """StampedLocks have no notion of ownership. Locks acquired in 1259 * one thread can be released or converted in another.""" 1260 */ 1261 public void testNoOwnership() throws Throwable { 1262 ArrayList<Future<?>> futures = new ArrayList<>(); 1263 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1264 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1265 StampedLock lock = new StampedLock(); 1266 long stamp = writeLocker.apply(lock); 1267 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 1268 public void realRun() { 1269 writeUnlocker.accept(lock, stamp); 1270 assertUnlocked(lock); 1271 assertFalse(lock.validate(stamp)); 1272 }})); 1273 } 1274 for (Future<?> future : futures) 1275 assertNull(future.get()); 1276 } 1277 1278 /** Tries out sample usage code from StampedLock javadoc. */ 1279 public void testSampleUsage() throws Throwable { 1280 class Point { 1281 private double x, y; 1282 private final StampedLock sl = new StampedLock(); 1283 1284 void move(double deltaX, double deltaY) { // an exclusively locked method 1285 long stamp = sl.writeLock(); 1286 try { 1287 x += deltaX; 1288 y += deltaY; 1289 } finally { 1290 sl.unlockWrite(stamp); 1291 } 1292 } 1293 1294 double distanceFromOrigin() { // A read-only method 1295 double currentX, currentY; 1296 long stamp = sl.tryOptimisticRead(); 1297 do { 1298 if (stamp == 0L) 1299 stamp = sl.readLock(); 1300 try { 1301 // possibly racy reads 1302 currentX = x; 1303 currentY = y; 1304 } finally { 1305 stamp = sl.tryConvertToOptimisticRead(stamp); 1306 } 1307 } while (stamp == 0); 1308 return Math.hypot(currentX, currentY); 1309 } 1310 1311 double distanceFromOrigin2() { 1312 long stamp = sl.tryOptimisticRead(); 1313 try { 1314 retryHoldingLock: 1315 for (;; stamp = sl.readLock()) { 1316 if (stamp == 0L) 1317 continue retryHoldingLock; 1318 // possibly racy reads 1319 double currentX = x; 1320 double currentY = y; 1321 if (!sl.validate(stamp)) 1322 continue retryHoldingLock; 1323 return Math.hypot(currentX, currentY); 1324 } 1325 } finally { 1326 if (StampedLock.isReadLockStamp(stamp)) 1327 sl.unlockRead(stamp); 1328 } 1329 } 1330 1331 void moveIfAtOrigin(double newX, double newY) { 1332 long stamp = sl.readLock(); 1333 try { 1334 while (x == 0.0 && y == 0.0) { 1335 long ws = sl.tryConvertToWriteLock(stamp); 1336 if (ws != 0L) { 1337 stamp = ws; 1338 x = newX; 1339 y = newY; 1340 return; 1341 } 1342 else { 1343 sl.unlockRead(stamp); 1344 stamp = sl.writeLock(); 1345 } 1346 } 1347 } finally { 1348 sl.unlock(stamp); 1349 } 1350 } 1351 } 1352 1353 Point p = new Point(); 1354 p.move(3.0, 4.0); 1355 assertEquals(5.0, p.distanceFromOrigin()); 1356 p.moveIfAtOrigin(5.0, 12.0); 1357 assertEquals(5.0, p.distanceFromOrigin2()); 1358 } 1359 1360 /** 1361 * Stamp inspection methods work as expected, and do not inspect 1362 * the state of the lock itself. 1363 */ 1364 public void testStampStateInspectionMethods() { 1365 StampedLock lock = new StampedLock(); 1366 1367 assertFalse(isWriteLockStamp(0L)); 1368 assertFalse(isReadLockStamp(0L)); 1369 assertFalse(isLockStamp(0L)); 1370 assertFalse(isOptimisticReadStamp(0L)); 1371 1372 { 1373 long stamp = lock.writeLock(); 1374 for (int i = 0; i < 2; i++) { 1375 assertTrue(isWriteLockStamp(stamp)); 1376 assertFalse(isReadLockStamp(stamp)); 1377 assertTrue(isLockStamp(stamp)); 1378 assertFalse(isOptimisticReadStamp(stamp)); 1379 if (i == 0) 1380 lock.unlockWrite(stamp); 1381 } 1382 } 1383 1384 { 1385 long stamp = lock.readLock(); 1386 for (int i = 0; i < 2; i++) { 1387 assertFalse(isWriteLockStamp(stamp)); 1388 assertTrue(isReadLockStamp(stamp)); 1389 assertTrue(isLockStamp(stamp)); 1390 assertFalse(isOptimisticReadStamp(stamp)); 1391 if (i == 0) 1392 lock.unlockRead(stamp); 1393 } 1394 } 1395 1396 { 1397 long optimisticStamp = lock.tryOptimisticRead(); 1398 long readStamp = lock.tryConvertToReadLock(optimisticStamp); 1399 long writeStamp = lock.tryConvertToWriteLock(readStamp); 1400 for (int i = 0; i < 2; i++) { 1401 assertFalse(isWriteLockStamp(optimisticStamp)); 1402 assertFalse(isReadLockStamp(optimisticStamp)); 1403 assertFalse(isLockStamp(optimisticStamp)); 1404 assertTrue(isOptimisticReadStamp(optimisticStamp)); 1405 1406 assertFalse(isWriteLockStamp(readStamp)); 1407 assertTrue(isReadLockStamp(readStamp)); 1408 assertTrue(isLockStamp(readStamp)); 1409 assertFalse(isOptimisticReadStamp(readStamp)); 1410 1411 assertTrue(isWriteLockStamp(writeStamp)); 1412 assertFalse(isReadLockStamp(writeStamp)); 1413 assertTrue(isLockStamp(writeStamp)); 1414 assertFalse(isOptimisticReadStamp(writeStamp)); 1415 if (i == 0) 1416 lock.unlockWrite(writeStamp); 1417 } 1418 } 1419 } 1420 1421 /** 1422 * Multiple threads repeatedly contend for the same lock. 1423 */ 1424 public void testConcurrentAccess() throws Exception { 1425 final StampedLock sl = new StampedLock(); 1426 final Lock wl = sl.asWriteLock(); 1427 final Lock rl = sl.asReadLock(); 1428 final long testDurationMillis = expensiveTests ? 1000 : 2; 1429 final int nTasks = ThreadLocalRandom.current().nextInt(1, 10); 1430 final AtomicBoolean done = new AtomicBoolean(false); 1431 final List<CompletableFuture> futures = new ArrayList<>(); 1432 final List<Callable<Long>> stampedWriteLockers = List.of( 1433 () -> sl.writeLock(), 1434 () -> writeLockInterruptiblyUninterrupted(sl), 1435 () -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), 1436 () -> { 1437 long stamp; 1438 do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); } 1439 while (stamp == 0L); 1440 return stamp; 1441 }, 1442 () -> { 1443 long stamp; 1444 do { stamp = sl.tryWriteLock(); } while (stamp == 0L); 1445 return stamp; 1446 }, 1447 () -> { 1448 long stamp; 1449 do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L); 1450 return stamp; 1451 }); 1452 final List<Callable<Long>> stampedReadLockers = List.of( 1453 () -> sl.readLock(), 1454 () -> readLockInterruptiblyUninterrupted(sl), 1455 () -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), 1456 () -> { 1457 long stamp; 1458 do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); } 1459 while (stamp == 0L); 1460 return stamp; 1461 }, 1462 () -> { 1463 long stamp; 1464 do { stamp = sl.tryReadLock(); } while (stamp == 0L); 1465 return stamp; 1466 }, 1467 () -> { 1468 long stamp; 1469 do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L); 1470 return stamp; 1471 }); 1472 final List<Consumer<Long>> stampedWriteUnlockers = List.of( 1473 stamp -> sl.unlockWrite(stamp), 1474 stamp -> sl.unlock(stamp), 1475 stamp -> assertTrue(sl.tryUnlockWrite()), 1476 stamp -> wl.unlock(), 1477 stamp -> sl.tryConvertToOptimisticRead(stamp)); 1478 final List<Consumer<Long>> stampedReadUnlockers = List.of( 1479 stamp -> sl.unlockRead(stamp), 1480 stamp -> sl.unlock(stamp), 1481 stamp -> assertTrue(sl.tryUnlockRead()), 1482 stamp -> rl.unlock(), 1483 stamp -> sl.tryConvertToOptimisticRead(stamp)); 1484 final Action writer = () -> { 1485 // repeatedly acquires write lock 1486 var locker = chooseRandomly(stampedWriteLockers); 1487 var unlocker = chooseRandomly(stampedWriteUnlockers); 1488 while (!done.getAcquire()) { 1489 long stamp = locker.call(); 1490 try { 1491 assertTrue(isWriteLockStamp(stamp)); 1492 assertTrue(sl.isWriteLocked()); 1493 assertFalse(isReadLockStamp(stamp)); 1494 assertFalse(sl.isReadLocked()); 1495 assertEquals(0, sl.getReadLockCount()); 1496 assertTrue(sl.validate(stamp)); 1497 } finally { 1498 unlocker.accept(stamp); 1499 } 1500 } 1501 }; 1502 final Action reader = () -> { 1503 // repeatedly acquires read lock 1504 var locker = chooseRandomly(stampedReadLockers); 1505 var unlocker = chooseRandomly(stampedReadUnlockers); 1506 while (!done.getAcquire()) { 1507 long stamp = locker.call(); 1508 try { 1509 assertFalse(isWriteLockStamp(stamp)); 1510 assertFalse(sl.isWriteLocked()); 1511 assertTrue(isReadLockStamp(stamp)); 1512 assertTrue(sl.isReadLocked()); 1513 assertTrue(sl.getReadLockCount() > 0); 1514 assertTrue(sl.validate(stamp)); 1515 } finally { 1516 unlocker.accept(stamp); 1517 } 1518 } 1519 }; 1520 for (int i = nTasks; i--> 0; ) { 1521 Action task = chooseRandomly(writer, reader); 1522 futures.add(CompletableFuture.runAsync(checkedRunnable(task))); 1523 } 1524 Thread.sleep(testDurationMillis); 1525 done.setRelease(true); 1526 for (var future : futures) 1527 checkTimedGet(future, null); 1528 } 1529 1530 }