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 s = 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 390 /** 391 * interruptible operations throw InterruptedException when read locked and interrupted 392 */ 393 public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() { 394 final StampedLock lock = new StampedLock(); 395 long s = lock.readLock(); 396 397 Action[] interruptibleLockBlockingActions = { 398 () -> lock.writeLockInterruptibly(), 399 () -> lock.tryWriteLock(Long.MAX_VALUE, DAYS), 400 () -> lock.asWriteLock().lockInterruptibly(), 401 () -> lock.asWriteLock().tryLock(Long.MAX_VALUE, DAYS), 402 }; 403 shuffle(interruptibleLockBlockingActions); 404 405 assertThrowInterruptedExceptionWhenInterrupted(interruptibleLockBlockingActions); 406 } 407 408 /** 409 * Non-interruptible operations ignore and preserve interrupt status 410 */ 411 public void testNonInterruptibleOperationsIgnoreInterrupts() { 412 final StampedLock lock = new StampedLock(); 413 Thread.currentThread().interrupt(); 414 415 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 416 long s = assertValid(lock, lock.readLock()); 417 readUnlocker.accept(lock, s); 418 s = assertValid(lock, lock.tryReadLock()); 419 readUnlocker.accept(lock, s); 420 } 421 422 lock.asReadLock().lock(); 423 lock.asReadLock().unlock(); 424 425 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 426 long s = assertValid(lock, lock.writeLock()); 427 writeUnlocker.accept(lock, s); 428 s = assertValid(lock, lock.tryWriteLock()); 429 writeUnlocker.accept(lock, s); 430 } 431 432 lock.asWriteLock().lock(); 433 lock.asWriteLock().unlock(); 434 435 assertTrue(Thread.interrupted()); 436 } 437 438 /** 439 * tryWriteLock on an unlocked lock succeeds 440 */ 441 public void testTryWriteLock() { 442 final StampedLock lock = new StampedLock(); 443 long s = lock.tryWriteLock(); 444 assertTrue(s != 0L); 445 assertTrue(lock.isWriteLocked()); 446 assertEquals(0L, lock.tryWriteLock()); 447 releaseWriteLock(lock, s); 448 } 449 450 /** 451 * tryWriteLock fails if locked 452 */ 453 public void testTryWriteLockWhenLocked() { 454 final StampedLock lock = new StampedLock(); 455 long s = lock.writeLock(); 456 Thread t = newStartedThread(new CheckedRunnable() { 457 public void realRun() { 458 assertEquals(0L, lock.tryWriteLock()); 459 }}); 460 461 assertEquals(0L, lock.tryWriteLock()); 462 awaitTermination(t); 463 releaseWriteLock(lock, s); 464 } 465 466 /** 467 * tryReadLock fails if write-locked 468 */ 469 public void testTryReadLockWhenLocked() { 470 final StampedLock lock = new StampedLock(); 471 long s = lock.writeLock(); 472 Thread t = newStartedThread(new CheckedRunnable() { 473 public void realRun() { 474 assertEquals(0L, lock.tryReadLock()); 475 }}); 476 477 assertEquals(0L, lock.tryReadLock()); 478 awaitTermination(t); 479 releaseWriteLock(lock, s); 480 } 481 482 /** 483 * Multiple threads can hold a read lock when not write-locked 484 */ 485 public void testMultipleReadLocks() { 486 final StampedLock lock = new StampedLock(); 487 final long s = lock.readLock(); 488 Thread t = newStartedThread(new CheckedRunnable() { 489 public void realRun() throws InterruptedException { 490 long s2 = lock.tryReadLock(); 491 assertValid(lock, s2); 492 lock.unlockRead(s2); 493 long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS); 494 assertValid(lock, s3); 495 lock.unlockRead(s3); 496 long s4 = lock.readLock(); 497 assertValid(lock, s4); 498 lock.unlockRead(s4); 499 lock.asReadLock().lock(); 500 lock.asReadLock().unlock(); 501 lock.asReadLock().lockInterruptibly(); 502 lock.asReadLock().unlock(); 503 lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS); 504 lock.asReadLock().unlock(); 505 }}); 506 507 awaitTermination(t); 508 lock.unlockRead(s); 509 } 510 511 /** 512 * writeLock() succeeds only after a reading thread unlocks 513 */ 514 public void testWriteAfterReadLock() throws InterruptedException { 515 final CountDownLatch aboutToLock = new CountDownLatch(1); 516 final StampedLock lock = new StampedLock(); 517 long rs = lock.readLock(); 518 Thread t = newStartedThread(new CheckedRunnable() { 519 public void realRun() { 520 aboutToLock.countDown(); 521 long s = lock.writeLock(); 522 assertTrue(lock.isWriteLocked()); 523 assertFalse(lock.isReadLocked()); 524 lock.unlockWrite(s); 525 }}); 526 527 await(aboutToLock); 528 assertThreadBlocks(t, Thread.State.WAITING); 529 assertFalse(lock.isWriteLocked()); 530 assertTrue(lock.isReadLocked()); 531 lock.unlockRead(rs); 532 awaitTermination(t); 533 assertUnlocked(lock); 534 } 535 536 /** 537 * writeLock() succeeds only after reading threads unlock 538 */ 539 public void testWriteAfterMultipleReadLocks() { 540 final StampedLock lock = new StampedLock(); 541 long s = lock.readLock(); 542 Thread t1 = newStartedThread(new CheckedRunnable() { 543 public void realRun() { 544 long rs = lock.readLock(); 545 lock.unlockRead(rs); 546 }}); 547 548 awaitTermination(t1); 549 550 Thread t2 = newStartedThread(new CheckedRunnable() { 551 public void realRun() { 552 long ws = lock.writeLock(); 553 lock.unlockWrite(ws); 554 }}); 555 556 assertTrue(lock.isReadLocked()); 557 assertFalse(lock.isWriteLocked()); 558 lock.unlockRead(s); 559 awaitTermination(t2); 560 assertUnlocked(lock); 561 } 562 563 /** 564 * readLock() succeed only after a writing thread unlocks 565 */ 566 public void testReadAfterWriteLock() { 567 final StampedLock lock = new StampedLock(); 568 final CountDownLatch threadsStarted = new CountDownLatch(2); 569 final long s = lock.writeLock(); 570 final Runnable acquireReleaseReadLock = new CheckedRunnable() { 571 public void realRun() { 572 threadsStarted.countDown(); 573 long rs = lock.readLock(); 574 assertTrue(lock.isReadLocked()); 575 assertFalse(lock.isWriteLocked()); 576 lock.unlockRead(rs); 577 }}; 578 Thread t1 = newStartedThread(acquireReleaseReadLock); 579 Thread t2 = newStartedThread(acquireReleaseReadLock); 580 581 await(threadsStarted); 582 assertThreadBlocks(t1, Thread.State.WAITING); 583 assertThreadBlocks(t2, Thread.State.WAITING); 584 assertTrue(lock.isWriteLocked()); 585 assertFalse(lock.isReadLocked()); 586 releaseWriteLock(lock, s); 587 awaitTermination(t1); 588 awaitTermination(t2); 589 assertUnlocked(lock); 590 } 591 592 /** 593 * tryReadLock succeeds if read locked but not write locked 594 */ 595 public void testTryLockWhenReadLocked() { 596 final StampedLock lock = new StampedLock(); 597 long s = lock.readLock(); 598 Thread t = newStartedThread(new CheckedRunnable() { 599 public void realRun() { 600 long rs = lock.tryReadLock(); 601 assertValid(lock, rs); 602 lock.unlockRead(rs); 603 }}); 604 605 awaitTermination(t); 606 lock.unlockRead(s); 607 } 608 609 /** 610 * tryWriteLock fails when read locked 611 */ 612 public void testTryWriteLockWhenReadLocked() { 613 final StampedLock lock = new StampedLock(); 614 long s = lock.readLock(); 615 Thread t = newStartedThread(new CheckedRunnable() { 616 public void realRun() { 617 assertEquals(0L, lock.tryWriteLock()); 618 }}); 619 620 awaitTermination(t); 621 lock.unlockRead(s); 622 } 623 624 /** 625 * timed lock operations time out if lock not available 626 */ 627 public void testTimedLock_Timeout() throws Exception { 628 ArrayList<Future<?>> futures = new ArrayList<>(); 629 630 // Write locked 631 final StampedLock lock = new StampedLock(); 632 long stamp = lock.writeLock(); 633 assertEquals(0L, lock.tryReadLock(0L, DAYS)); 634 assertEquals(0L, lock.tryReadLock(Long.MIN_VALUE, DAYS)); 635 assertFalse(lock.asReadLock().tryLock(0L, DAYS)); 636 assertFalse(lock.asReadLock().tryLock(Long.MIN_VALUE, DAYS)); 637 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 638 assertEquals(0L, lock.tryWriteLock(Long.MIN_VALUE, DAYS)); 639 assertFalse(lock.asWriteLock().tryLock(0L, DAYS)); 640 assertFalse(lock.asWriteLock().tryLock(Long.MIN_VALUE, DAYS)); 641 642 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 643 public void realRun() throws InterruptedException { 644 long startTime = System.nanoTime(); 645 assertEquals(0L, lock.tryWriteLock(timeoutMillis(), MILLISECONDS)); 646 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 647 }})); 648 649 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 650 public void realRun() throws InterruptedException { 651 long startTime = System.nanoTime(); 652 assertEquals(0L, lock.tryReadLock(timeoutMillis(), MILLISECONDS)); 653 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 654 }})); 655 656 // Read locked 657 final StampedLock lock2 = new StampedLock(); 658 long stamp2 = lock2.readLock(); 659 assertEquals(0L, lock2.tryWriteLock(0L, DAYS)); 660 assertEquals(0L, lock2.tryWriteLock(Long.MIN_VALUE, DAYS)); 661 assertFalse(lock2.asWriteLock().tryLock(0L, DAYS)); 662 assertFalse(lock2.asWriteLock().tryLock(Long.MIN_VALUE, DAYS)); 663 664 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 665 public void realRun() throws InterruptedException { 666 long startTime = System.nanoTime(); 667 assertEquals(0L, lock2.tryWriteLock(timeoutMillis(), MILLISECONDS)); 668 assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); 669 }})); 670 671 for (Future<?> future : futures) 672 assertNull(future.get()); 673 674 releaseWriteLock(lock, stamp); 675 releaseReadLock(lock2, stamp2); 676 } 677 678 /** 679 * writeLockInterruptibly succeeds if unlocked 680 */ 681 public void testWriteLockInterruptibly() throws InterruptedException { 682 final StampedLock lock = new StampedLock(); 683 long s = lock.writeLockInterruptibly(); 684 assertTrue(lock.isWriteLocked()); 685 releaseWriteLock(lock, s); 686 } 687 688 /** 689 * readLockInterruptibly succeeds if lock free 690 */ 691 public void testReadLockInterruptibly() throws InterruptedException { 692 final StampedLock lock = new StampedLock(); 693 694 long s = assertValid(lock, lock.readLockInterruptibly()); 695 assertTrue(lock.isReadLocked()); 696 lock.unlockRead(s); 697 698 lock.asReadLock().lockInterruptibly(); 699 assertTrue(lock.isReadLocked()); 700 lock.asReadLock().unlock(); 701 } 702 703 /** 704 * A serialized lock deserializes as unlocked 705 */ 706 public void testSerialization() { 707 StampedLock lock = new StampedLock(); 708 lock.writeLock(); 709 StampedLock clone = serialClone(lock); 710 assertTrue(lock.isWriteLocked()); 711 assertFalse(clone.isWriteLocked()); 712 long s = clone.writeLock(); 713 assertTrue(clone.isWriteLocked()); 714 clone.unlockWrite(s); 715 assertFalse(clone.isWriteLocked()); 716 } 717 718 /** 719 * toString indicates current lock state 720 */ 721 public void testToString() { 722 StampedLock lock = new StampedLock(); 723 assertTrue(lock.toString().contains("Unlocked")); 724 long s = lock.writeLock(); 725 assertTrue(lock.toString().contains("Write-locked")); 726 lock.unlockWrite(s); 727 s = lock.readLock(); 728 assertTrue(lock.toString().contains("Read-locks")); 729 } 730 731 /** 732 * tryOptimisticRead succeeds and validates if unlocked, fails if 733 * exclusively locked 734 */ 735 public void testValidateOptimistic() throws InterruptedException { 736 StampedLock lock = new StampedLock(); 737 738 assertValid(lock, lock.tryOptimisticRead()); 739 740 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 741 long s = assertValid(lock, writeLocker.apply(lock)); 742 assertEquals(0L, lock.tryOptimisticRead()); 743 releaseWriteLock(lock, s); 744 } 745 746 for (Function<StampedLock, Long> readLocker : readLockers()) { 747 long s = assertValid(lock, readLocker.apply(lock)); 748 long p = assertValid(lock, lock.tryOptimisticRead()); 749 releaseReadLock(lock, s); 750 assertTrue(lock.validate(p)); 751 } 752 753 assertValid(lock, lock.tryOptimisticRead()); 754 } 755 756 /** 757 * tryOptimisticRead stamp does not validate if a write lock intervenes 758 */ 759 public void testValidateOptimisticWriteLocked() { 760 final StampedLock lock = new StampedLock(); 761 final long p = assertValid(lock, lock.tryOptimisticRead()); 762 final long s = assertValid(lock, lock.writeLock()); 763 assertFalse(lock.validate(p)); 764 assertEquals(0L, lock.tryOptimisticRead()); 765 assertTrue(lock.validate(s)); 766 lock.unlockWrite(s); 767 } 768 769 /** 770 * tryOptimisticRead stamp does not validate if a write lock 771 * intervenes in another thread 772 */ 773 public void testValidateOptimisticWriteLocked2() 774 throws InterruptedException { 775 final CountDownLatch locked = new CountDownLatch(1); 776 final StampedLock lock = new StampedLock(); 777 final long p = assertValid(lock, lock.tryOptimisticRead()); 778 779 Thread t = newStartedThread(new CheckedInterruptedRunnable() { 780 public void realRun() throws InterruptedException { 781 lock.writeLockInterruptibly(); 782 locked.countDown(); 783 lock.writeLockInterruptibly(); 784 }}); 785 786 await(locked); 787 assertFalse(lock.validate(p)); 788 assertEquals(0L, lock.tryOptimisticRead()); 789 assertThreadBlocks(t, Thread.State.WAITING); 790 t.interrupt(); 791 awaitTermination(t); 792 assertTrue(lock.isWriteLocked()); 793 } 794 795 /** 796 * tryConvertToOptimisticRead succeeds and validates if successfully locked 797 */ 798 public void testTryConvertToOptimisticRead() throws InterruptedException { 799 StampedLock lock = new StampedLock(); 800 long s, p, q; 801 assertEquals(0L, lock.tryConvertToOptimisticRead(0L)); 802 803 s = assertValid(lock, lock.tryOptimisticRead()); 804 assertEquals(s, lock.tryConvertToOptimisticRead(s)); 805 assertTrue(lock.validate(s)); 806 807 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 808 s = assertValid(lock, writeLocker.apply(lock)); 809 p = assertValid(lock, lock.tryConvertToOptimisticRead(s)); 810 assertFalse(lock.validate(s)); 811 assertTrue(lock.validate(p)); 812 assertUnlocked(lock); 813 } 814 815 for (Function<StampedLock, Long> readLocker : readLockers()) { 816 s = assertValid(lock, readLocker.apply(lock)); 817 q = assertValid(lock, lock.tryOptimisticRead()); 818 assertEquals(q, lock.tryConvertToOptimisticRead(q)); 819 assertTrue(lock.validate(q)); 820 assertTrue(lock.isReadLocked()); 821 p = assertValid(lock, lock.tryConvertToOptimisticRead(s)); 822 assertTrue(lock.validate(p)); 823 assertTrue(lock.validate(s)); 824 assertUnlocked(lock); 825 assertEquals(q, lock.tryConvertToOptimisticRead(q)); 826 assertTrue(lock.validate(q)); 827 } 828 } 829 830 /** 831 * tryConvertToReadLock succeeds for valid stamps 832 */ 833 public void testTryConvertToReadLock() throws InterruptedException { 834 StampedLock lock = new StampedLock(); 835 long s, p; 836 837 assertEquals(0L, lock.tryConvertToReadLock(0L)); 838 839 s = assertValid(lock, lock.tryOptimisticRead()); 840 p = assertValid(lock, lock.tryConvertToReadLock(s)); 841 assertTrue(lock.isReadLocked()); 842 assertEquals(1, lock.getReadLockCount()); 843 assertTrue(lock.validate(s)); 844 lock.unlockRead(p); 845 846 s = assertValid(lock, lock.tryOptimisticRead()); 847 lock.readLock(); 848 p = assertValid(lock, lock.tryConvertToReadLock(s)); 849 assertTrue(lock.isReadLocked()); 850 assertEquals(2, lock.getReadLockCount()); 851 lock.unlockRead(p); 852 lock.unlockRead(p); 853 assertUnlocked(lock); 854 855 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 856 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 857 s = assertValid(lock, writeLocker.apply(lock)); 858 p = assertValid(lock, lock.tryConvertToReadLock(s)); 859 assertFalse(lock.validate(s)); 860 assertTrue(lock.isReadLocked()); 861 assertEquals(1, lock.getReadLockCount()); 862 readUnlocker.accept(lock, p); 863 } 864 865 for (Function<StampedLock, Long> readLocker : readLockers()) { 866 s = assertValid(lock, readLocker.apply(lock)); 867 assertEquals(s, lock.tryConvertToReadLock(s)); 868 assertTrue(lock.validate(s)); 869 assertTrue(lock.isReadLocked()); 870 assertEquals(1, lock.getReadLockCount()); 871 readUnlocker.accept(lock, s); 872 } 873 } 874 } 875 876 /** 877 * tryConvertToWriteLock succeeds if lock available; fails if multiply read locked 878 */ 879 public void testTryConvertToWriteLock() throws InterruptedException { 880 StampedLock lock = new StampedLock(); 881 long s, p; 882 883 assertEquals(0L, lock.tryConvertToWriteLock(0L)); 884 885 assertTrue((s = lock.tryOptimisticRead()) != 0L); 886 assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); 887 assertTrue(lock.isWriteLocked()); 888 lock.unlockWrite(p); 889 890 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 891 for (Function<StampedLock, Long> writeLocker : writeLockers()) { 892 s = assertValid(lock, writeLocker.apply(lock)); 893 assertEquals(s, lock.tryConvertToWriteLock(s)); 894 assertTrue(lock.validate(s)); 895 assertTrue(lock.isWriteLocked()); 896 writeUnlocker.accept(lock, s); 897 } 898 899 for (Function<StampedLock, Long> readLocker : readLockers()) { 900 s = assertValid(lock, readLocker.apply(lock)); 901 p = assertValid(lock, lock.tryConvertToWriteLock(s)); 902 assertFalse(lock.validate(s)); 903 assertTrue(lock.validate(p)); 904 assertTrue(lock.isWriteLocked()); 905 writeUnlocker.accept(lock, p); 906 } 907 } 908 909 // failure if multiply read locked 910 for (Function<StampedLock, Long> readLocker : readLockers()) { 911 s = assertValid(lock, readLocker.apply(lock)); 912 p = assertValid(lock, readLocker.apply(lock)); 913 assertEquals(0L, lock.tryConvertToWriteLock(s)); 914 assertTrue(lock.validate(s)); 915 assertTrue(lock.validate(p)); 916 assertEquals(2, lock.getReadLockCount()); 917 lock.unlock(p); 918 lock.unlock(s); 919 assertUnlocked(lock); 920 } 921 } 922 923 /** 924 * asWriteLock can be locked and unlocked 925 */ 926 public void testAsWriteLock() throws Throwable { 927 StampedLock sl = new StampedLock(); 928 Lock lock = sl.asWriteLock(); 929 for (Action locker : lockLockers(lock)) { 930 locker.run(); 931 assertTrue(sl.isWriteLocked()); 932 assertFalse(sl.isReadLocked()); 933 assertFalse(lock.tryLock()); 934 lock.unlock(); 935 assertUnlocked(sl); 936 } 937 } 938 939 /** 940 * asReadLock can be locked and unlocked 941 */ 942 public void testAsReadLock() throws Throwable { 943 StampedLock sl = new StampedLock(); 944 Lock lock = sl.asReadLock(); 945 for (Action locker : lockLockers(lock)) { 946 locker.run(); 947 assertTrue(sl.isReadLocked()); 948 assertFalse(sl.isWriteLocked()); 949 assertEquals(1, sl.getReadLockCount()); 950 locker.run(); 951 assertTrue(sl.isReadLocked()); 952 assertEquals(2, sl.getReadLockCount()); 953 lock.unlock(); 954 lock.unlock(); 955 assertUnlocked(sl); 956 } 957 } 958 959 /** 960 * asReadWriteLock.writeLock can be locked and unlocked 961 */ 962 public void testAsReadWriteLockWriteLock() throws Throwable { 963 StampedLock sl = new StampedLock(); 964 Lock lock = sl.asReadWriteLock().writeLock(); 965 for (Action locker : lockLockers(lock)) { 966 locker.run(); 967 assertTrue(sl.isWriteLocked()); 968 assertFalse(sl.isReadLocked()); 969 assertFalse(lock.tryLock()); 970 lock.unlock(); 971 assertUnlocked(sl); 972 } 973 } 974 975 /** 976 * asReadWriteLock.readLock can be locked and unlocked 977 */ 978 public void testAsReadWriteLockReadLock() throws Throwable { 979 StampedLock sl = new StampedLock(); 980 Lock lock = sl.asReadWriteLock().readLock(); 981 for (Action locker : lockLockers(lock)) { 982 locker.run(); 983 assertTrue(sl.isReadLocked()); 984 assertFalse(sl.isWriteLocked()); 985 assertEquals(1, sl.getReadLockCount()); 986 locker.run(); 987 assertTrue(sl.isReadLocked()); 988 assertEquals(2, sl.getReadLockCount()); 989 lock.unlock(); 990 lock.unlock(); 991 assertUnlocked(sl); 992 } 993 } 994 995 /** 996 * Lock.newCondition throws UnsupportedOperationException 997 */ 998 public void testLockViewsDoNotSupportConditions() { 999 StampedLock sl = new StampedLock(); 1000 assertThrows(UnsupportedOperationException.class, 1001 () -> sl.asWriteLock().newCondition(), 1002 () -> sl.asReadLock().newCondition(), 1003 () -> sl.asReadWriteLock().writeLock().newCondition(), 1004 () -> sl.asReadWriteLock().readLock().newCondition()); 1005 } 1006 1007 /** 1008 * Passing optimistic read stamps to unlock operations result in 1009 * IllegalMonitorStateException 1010 */ 1011 public void testCannotUnlockOptimisticReadStamps() { 1012 { 1013 StampedLock sl = new StampedLock(); 1014 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1015 assertThrows(IllegalMonitorStateException.class, 1016 () -> sl.unlockRead(stamp)); 1017 } 1018 { 1019 StampedLock sl = new StampedLock(); 1020 long stamp = sl.tryOptimisticRead(); 1021 assertThrows(IllegalMonitorStateException.class, 1022 () -> sl.unlock(stamp)); 1023 } 1024 1025 { 1026 StampedLock sl = new StampedLock(); 1027 long stamp = sl.tryOptimisticRead(); 1028 sl.writeLock(); 1029 assertThrows(IllegalMonitorStateException.class, 1030 () -> sl.unlock(stamp)); 1031 } 1032 { 1033 StampedLock sl = new StampedLock(); 1034 sl.readLock(); 1035 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1036 assertThrows(IllegalMonitorStateException.class, 1037 () -> sl.unlockRead(stamp)); 1038 } 1039 { 1040 StampedLock sl = new StampedLock(); 1041 sl.readLock(); 1042 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1043 assertThrows(IllegalMonitorStateException.class, 1044 () -> sl.unlock(stamp)); 1045 } 1046 1047 { 1048 StampedLock sl = new StampedLock(); 1049 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1050 assertValid(sl, stamp); 1051 sl.writeLock(); 1052 assertThrows(IllegalMonitorStateException.class, 1053 () -> sl.unlockWrite(stamp)); 1054 } 1055 { 1056 StampedLock sl = new StampedLock(); 1057 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1058 sl.writeLock(); 1059 assertThrows(IllegalMonitorStateException.class, 1060 () -> sl.unlock(stamp)); 1061 } 1062 { 1063 StampedLock sl = new StampedLock(); 1064 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1065 sl.readLock(); 1066 assertThrows(IllegalMonitorStateException.class, 1067 () -> sl.unlockRead(stamp)); 1068 } 1069 { 1070 StampedLock sl = new StampedLock(); 1071 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1072 sl.readLock(); 1073 assertThrows(IllegalMonitorStateException.class, 1074 () -> sl.unlock(stamp)); 1075 } 1076 1077 { 1078 StampedLock sl = new StampedLock(); 1079 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1080 assertValid(sl, stamp); 1081 sl.writeLock(); 1082 assertThrows(IllegalMonitorStateException.class, 1083 () -> sl.unlockWrite(stamp)); 1084 } 1085 { 1086 StampedLock sl = new StampedLock(); 1087 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1088 sl.writeLock(); 1089 assertThrows(IllegalMonitorStateException.class, 1090 () -> sl.unlock(stamp)); 1091 } 1092 { 1093 StampedLock sl = new StampedLock(); 1094 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1095 sl.readLock(); 1096 assertThrows(IllegalMonitorStateException.class, 1097 () -> sl.unlockRead(stamp)); 1098 } 1099 { 1100 StampedLock sl = new StampedLock(); 1101 sl.readLock(); 1102 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1103 assertValid(sl, stamp); 1104 sl.readLock(); 1105 assertThrows(IllegalMonitorStateException.class, 1106 () -> sl.unlockRead(stamp)); 1107 } 1108 { 1109 StampedLock sl = new StampedLock(); 1110 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1111 sl.readLock(); 1112 assertThrows(IllegalMonitorStateException.class, 1113 () -> sl.unlock(stamp)); 1114 } 1115 { 1116 StampedLock sl = new StampedLock(); 1117 sl.readLock(); 1118 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1119 sl.readLock(); 1120 assertThrows(IllegalMonitorStateException.class, 1121 () -> sl.unlock(stamp)); 1122 } 1123 } 1124 1125 static long writeLockInterruptiblyUninterrupted(StampedLock sl) { 1126 try { return sl.writeLockInterruptibly(); } 1127 catch (InterruptedException ex) { throw new AssertionError(ex); } 1128 } 1129 1130 static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1131 try { return sl.tryWriteLock(time, unit); } 1132 catch (InterruptedException ex) { throw new AssertionError(ex); } 1133 } 1134 1135 static long readLockInterruptiblyUninterrupted(StampedLock sl) { 1136 try { return sl.readLockInterruptibly(); } 1137 catch (InterruptedException ex) { throw new AssertionError(ex); } 1138 } 1139 1140 static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1141 try { return sl.tryReadLock(time, unit); } 1142 catch (InterruptedException ex) { throw new AssertionError(ex); } 1143 } 1144 1145 /** 1146 * Invalid stamps result in IllegalMonitorStateException 1147 */ 1148 public void testInvalidStampsThrowIllegalMonitorStateException() { 1149 final StampedLock sl = new StampedLock(); 1150 1151 assertThrows(IllegalMonitorStateException.class, 1152 () -> sl.unlockWrite(0L), 1153 () -> sl.unlockRead(0L), 1154 () -> sl.unlock(0L)); 1155 1156 final long optimisticStamp = sl.tryOptimisticRead(); 1157 final long readStamp = sl.readLock(); 1158 sl.unlockRead(readStamp); 1159 final long writeStamp = sl.writeLock(); 1160 sl.unlockWrite(writeStamp); 1161 assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L); 1162 final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp }; 1163 final Runnable assertNoLongerValidStampsThrow = () -> { 1164 for (long noLongerValidStamp : noLongerValidStamps) 1165 assertThrows(IllegalMonitorStateException.class, 1166 () -> sl.unlockWrite(noLongerValidStamp), 1167 () -> sl.unlockRead(noLongerValidStamp), 1168 () -> sl.unlock(noLongerValidStamp)); 1169 }; 1170 assertNoLongerValidStampsThrow.run(); 1171 1172 for (Function<StampedLock, Long> readLocker : readLockers()) 1173 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 1174 final long stamp = readLocker.apply(sl); 1175 assertValid(sl, stamp); 1176 assertNoLongerValidStampsThrow.run(); 1177 assertThrows(IllegalMonitorStateException.class, 1178 () -> sl.unlockWrite(stamp), 1179 () -> sl.unlockRead(sl.tryOptimisticRead()), 1180 () -> sl.unlockRead(0L)); 1181 readUnlocker.accept(sl, stamp); 1182 assertUnlocked(sl); 1183 assertNoLongerValidStampsThrow.run(); 1184 } 1185 1186 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1187 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1188 final long stamp = writeLocker.apply(sl); 1189 assertValid(sl, stamp); 1190 assertNoLongerValidStampsThrow.run(); 1191 assertThrows(IllegalMonitorStateException.class, 1192 () -> sl.unlockRead(stamp), 1193 () -> sl.unlockWrite(0L)); 1194 writeUnlocker.accept(sl, stamp); 1195 assertUnlocked(sl); 1196 assertNoLongerValidStampsThrow.run(); 1197 } 1198 } 1199 1200 /** 1201 * Read locks can be very deeply nested 1202 */ 1203 public void testDeeplyNestedReadLocks() { 1204 final StampedLock lock = new StampedLock(); 1205 final int depth = 300; 1206 final long[] stamps = new long[depth]; 1207 final List<Function<StampedLock, Long>> readLockers = readLockers(); 1208 final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers(); 1209 for (int i = 0; i < depth; i++) { 1210 Function<StampedLock, Long> readLocker 1211 = readLockers.get(i % readLockers.size()); 1212 long stamp = readLocker.apply(lock); 1213 assertEquals(i + 1, lock.getReadLockCount()); 1214 assertTrue(lock.isReadLocked()); 1215 stamps[i] = stamp; 1216 } 1217 for (int i = 0; i < depth; i++) { 1218 BiConsumer<StampedLock, Long> readUnlocker 1219 = readUnlockers.get(i % readUnlockers.size()); 1220 assertEquals(depth - i, lock.getReadLockCount()); 1221 assertTrue(lock.isReadLocked()); 1222 readUnlocker.accept(lock, stamps[depth - 1 - i]); 1223 } 1224 assertUnlocked(lock); 1225 } 1226 1227 /** 1228 * Stamped locks are not reentrant. 1229 */ 1230 public void testNonReentrant() throws InterruptedException { 1231 final StampedLock lock = new StampedLock(); 1232 long stamp; 1233 1234 stamp = lock.writeLock(); 1235 assertValid(lock, stamp); 1236 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1237 assertEquals(0L, lock.tryReadLock(0L, DAYS)); 1238 assertValid(lock, stamp); 1239 lock.unlockWrite(stamp); 1240 1241 stamp = lock.tryWriteLock(1L, DAYS); 1242 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1243 assertValid(lock, stamp); 1244 lock.unlockWrite(stamp); 1245 1246 stamp = lock.readLock(); 1247 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1248 assertValid(lock, stamp); 1249 lock.unlockRead(stamp); 1250 } 1251 1252 /** 1253 * """StampedLocks have no notion of ownership. Locks acquired in 1254 * one thread can be released or converted in another.""" 1255 */ 1256 public void testNoOwnership() throws Throwable { 1257 ArrayList<Future<?>> futures = new ArrayList<>(); 1258 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1259 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1260 StampedLock lock = new StampedLock(); 1261 long stamp = writeLocker.apply(lock); 1262 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 1263 public void realRun() { 1264 writeUnlocker.accept(lock, stamp); 1265 assertUnlocked(lock); 1266 assertFalse(lock.validate(stamp)); 1267 }})); 1268 } 1269 for (Future<?> future : futures) 1270 assertNull(future.get()); 1271 } 1272 1273 /** Tries out sample usage code from StampedLock javadoc. */ 1274 public void testSampleUsage() throws Throwable { 1275 class Point { 1276 private double x, y; 1277 private final StampedLock sl = new StampedLock(); 1278 1279 void move(double deltaX, double deltaY) { // an exclusively locked method 1280 long stamp = sl.writeLock(); 1281 try { 1282 x += deltaX; 1283 y += deltaY; 1284 } finally { 1285 sl.unlockWrite(stamp); 1286 } 1287 } 1288 1289 double distanceFromOrigin() { // A read-only method 1290 double currentX, currentY; 1291 long stamp = sl.tryOptimisticRead(); 1292 do { 1293 if (stamp == 0L) 1294 stamp = sl.readLock(); 1295 try { 1296 // possibly racy reads 1297 currentX = x; 1298 currentY = y; 1299 } finally { 1300 stamp = sl.tryConvertToOptimisticRead(stamp); 1301 } 1302 } while (stamp == 0); 1303 return Math.hypot(currentX, currentY); 1304 } 1305 1306 double distanceFromOrigin2() { 1307 long stamp = sl.tryOptimisticRead(); 1308 try { 1309 retryHoldingLock: 1310 for (;; stamp = sl.readLock()) { 1311 if (stamp == 0L) 1312 continue retryHoldingLock; 1313 // possibly racy reads 1314 double currentX = x; 1315 double currentY = y; 1316 if (!sl.validate(stamp)) 1317 continue retryHoldingLock; 1318 return Math.hypot(currentX, currentY); 1319 } 1320 } finally { 1321 if (StampedLock.isReadLockStamp(stamp)) 1322 sl.unlockRead(stamp); 1323 } 1324 } 1325 1326 void moveIfAtOrigin(double newX, double newY) { 1327 long stamp = sl.readLock(); 1328 try { 1329 while (x == 0.0 && y == 0.0) { 1330 long ws = sl.tryConvertToWriteLock(stamp); 1331 if (ws != 0L) { 1332 stamp = ws; 1333 x = newX; 1334 y = newY; 1335 return; 1336 } 1337 else { 1338 sl.unlockRead(stamp); 1339 stamp = sl.writeLock(); 1340 } 1341 } 1342 } finally { 1343 sl.unlock(stamp); 1344 } 1345 } 1346 } 1347 1348 Point p = new Point(); 1349 p.move(3.0, 4.0); 1350 assertEquals(5.0, p.distanceFromOrigin()); 1351 p.moveIfAtOrigin(5.0, 12.0); 1352 assertEquals(5.0, p.distanceFromOrigin2()); 1353 } 1354 1355 /** 1356 * Stamp inspection methods work as expected, and do not inspect 1357 * the state of the lock itself. 1358 */ 1359 public void testStampStateInspectionMethods() { 1360 StampedLock lock = new StampedLock(); 1361 1362 assertFalse(isWriteLockStamp(0L)); 1363 assertFalse(isReadLockStamp(0L)); 1364 assertFalse(isLockStamp(0L)); 1365 assertFalse(isOptimisticReadStamp(0L)); 1366 1367 { 1368 long stamp = lock.writeLock(); 1369 for (int i = 0; i < 2; i++) { 1370 assertTrue(isWriteLockStamp(stamp)); 1371 assertFalse(isReadLockStamp(stamp)); 1372 assertTrue(isLockStamp(stamp)); 1373 assertFalse(isOptimisticReadStamp(stamp)); 1374 if (i == 0) 1375 lock.unlockWrite(stamp); 1376 } 1377 } 1378 1379 { 1380 long stamp = lock.readLock(); 1381 for (int i = 0; i < 2; i++) { 1382 assertFalse(isWriteLockStamp(stamp)); 1383 assertTrue(isReadLockStamp(stamp)); 1384 assertTrue(isLockStamp(stamp)); 1385 assertFalse(isOptimisticReadStamp(stamp)); 1386 if (i == 0) 1387 lock.unlockRead(stamp); 1388 } 1389 } 1390 1391 { 1392 long optimisticStamp = lock.tryOptimisticRead(); 1393 long readStamp = lock.tryConvertToReadLock(optimisticStamp); 1394 long writeStamp = lock.tryConvertToWriteLock(readStamp); 1395 for (int i = 0; i < 2; i++) { 1396 assertFalse(isWriteLockStamp(optimisticStamp)); 1397 assertFalse(isReadLockStamp(optimisticStamp)); 1398 assertFalse(isLockStamp(optimisticStamp)); 1399 assertTrue(isOptimisticReadStamp(optimisticStamp)); 1400 1401 assertFalse(isWriteLockStamp(readStamp)); 1402 assertTrue(isReadLockStamp(readStamp)); 1403 assertTrue(isLockStamp(readStamp)); 1404 assertFalse(isOptimisticReadStamp(readStamp)); 1405 1406 assertTrue(isWriteLockStamp(writeStamp)); 1407 assertFalse(isReadLockStamp(writeStamp)); 1408 assertTrue(isLockStamp(writeStamp)); 1409 assertFalse(isOptimisticReadStamp(writeStamp)); 1410 if (i == 0) 1411 lock.unlockWrite(writeStamp); 1412 } 1413 } 1414 } 1415 1416 /** 1417 * Multiple threads repeatedly contend for the same lock. 1418 */ 1419 public void testConcurrentAccess() throws Exception { 1420 final StampedLock sl = new StampedLock(); 1421 final Lock wl = sl.asWriteLock(); 1422 final Lock rl = sl.asReadLock(); 1423 final long testDurationMillis = expensiveTests ? 1000 : 2; 1424 final int nTasks = ThreadLocalRandom.current().nextInt(1, 10); 1425 final AtomicBoolean done = new AtomicBoolean(false); 1426 final List<CompletableFuture> futures = new ArrayList<>(); 1427 final List<Callable<Long>> stampedWriteLockers = List.of( 1428 () -> sl.writeLock(), 1429 () -> writeLockInterruptiblyUninterrupted(sl), 1430 () -> tryWriteLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), 1431 () -> { 1432 long stamp; 1433 do { stamp = sl.tryConvertToWriteLock(sl.tryOptimisticRead()); } 1434 while (stamp == 0L); 1435 return stamp; 1436 }, 1437 () -> { 1438 long stamp; 1439 do { stamp = sl.tryWriteLock(); } while (stamp == 0L); 1440 return stamp; 1441 }, 1442 () -> { 1443 long stamp; 1444 do { stamp = sl.tryWriteLock(0L, DAYS); } while (stamp == 0L); 1445 return stamp; 1446 }); 1447 final List<Callable<Long>> stampedReadLockers = List.of( 1448 () -> sl.readLock(), 1449 () -> readLockInterruptiblyUninterrupted(sl), 1450 () -> tryReadLockUninterrupted(sl, LONG_DELAY_MS, MILLISECONDS), 1451 () -> { 1452 long stamp; 1453 do { stamp = sl.tryConvertToReadLock(sl.tryOptimisticRead()); } 1454 while (stamp == 0L); 1455 return stamp; 1456 }, 1457 () -> { 1458 long stamp; 1459 do { stamp = sl.tryReadLock(); } while (stamp == 0L); 1460 return stamp; 1461 }, 1462 () -> { 1463 long stamp; 1464 do { stamp = sl.tryReadLock(0L, DAYS); } while (stamp == 0L); 1465 return stamp; 1466 }); 1467 final List<Consumer<Long>> stampedWriteUnlockers = List.of( 1468 stamp -> sl.unlockWrite(stamp), 1469 stamp -> sl.unlock(stamp), 1470 stamp -> assertTrue(sl.tryUnlockWrite()), 1471 stamp -> wl.unlock(), 1472 stamp -> sl.tryConvertToOptimisticRead(stamp)); 1473 final List<Consumer<Long>> stampedReadUnlockers = List.of( 1474 stamp -> sl.unlockRead(stamp), 1475 stamp -> sl.unlock(stamp), 1476 stamp -> assertTrue(sl.tryUnlockRead()), 1477 stamp -> rl.unlock(), 1478 stamp -> sl.tryConvertToOptimisticRead(stamp)); 1479 final Action writer = () -> { 1480 // repeatedly acquires write lock 1481 var locker = chooseRandomly(stampedWriteLockers); 1482 var unlocker = chooseRandomly(stampedWriteUnlockers); 1483 while (!done.getAcquire()) { 1484 long stamp = locker.call(); 1485 try { 1486 assertTrue(isWriteLockStamp(stamp)); 1487 assertTrue(sl.isWriteLocked()); 1488 assertFalse(isReadLockStamp(stamp)); 1489 assertFalse(sl.isReadLocked()); 1490 assertEquals(0, sl.getReadLockCount()); 1491 assertTrue(sl.validate(stamp)); 1492 } finally { 1493 unlocker.accept(stamp); 1494 } 1495 } 1496 }; 1497 final Action reader = () -> { 1498 // repeatedly acquires read lock 1499 var locker = chooseRandomly(stampedReadLockers); 1500 var unlocker = chooseRandomly(stampedReadUnlockers); 1501 while (!done.getAcquire()) { 1502 long stamp = locker.call(); 1503 try { 1504 assertFalse(isWriteLockStamp(stamp)); 1505 assertFalse(sl.isWriteLocked()); 1506 assertTrue(isReadLockStamp(stamp)); 1507 assertTrue(sl.isReadLocked()); 1508 assertTrue(sl.getReadLockCount() > 0); 1509 assertTrue(sl.validate(stamp)); 1510 } finally { 1511 unlocker.accept(stamp); 1512 } 1513 } 1514 }; 1515 for (int i = nTasks; i--> 0; ) { 1516 Action task = chooseRandomly(writer, reader); 1517 futures.add(CompletableFuture.runAsync(checkedRunnable(task))); 1518 } 1519 Thread.sleep(testDurationMillis); 1520 done.setRelease(true); 1521 for (var future : futures) 1522 checkTimedGet(future, null); 1523 } 1524 1525 }