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.CountDownLatch; 46 import java.util.concurrent.Future; 47 import java.util.concurrent.TimeUnit; 48 import java.util.concurrent.locks.Lock; 49 import java.util.concurrent.locks.StampedLock; 50 import java.util.function.BiConsumer; 51 import java.util.function.Function; 52 53 import junit.framework.Test; 54 import junit.framework.TestSuite; 55 56 public class StampedLockTest extends JSR166TestCase { main(String[] args)57 public static void main(String[] args) { 58 main(suite(), args); 59 } suite()60 public static Test suite() { 61 return new TestSuite(StampedLockTest.class); 62 } 63 64 /** 65 * Releases write lock, checking isWriteLocked before and after 66 */ releaseWriteLock(StampedLock lock, long stamp)67 void releaseWriteLock(StampedLock lock, long stamp) { 68 assertTrue(lock.isWriteLocked()); 69 assertValid(lock, stamp); 70 lock.unlockWrite(stamp); 71 assertFalse(lock.isWriteLocked()); 72 assertFalse(lock.validate(stamp)); 73 } 74 75 /** 76 * Releases read lock, checking isReadLocked before and after 77 */ releaseReadLock(StampedLock lock, long stamp)78 void releaseReadLock(StampedLock lock, long stamp) { 79 assertTrue(lock.isReadLocked()); 80 assertValid(lock, stamp); 81 lock.unlockRead(stamp); 82 assertFalse(lock.isReadLocked()); 83 assertTrue(lock.validate(stamp)); 84 } 85 assertNonZero(long v)86 long assertNonZero(long v) { 87 assertTrue(v != 0L); 88 return v; 89 } 90 assertValid(StampedLock lock, long stamp)91 long assertValid(StampedLock lock, long stamp) { 92 assertTrue(stamp != 0L); 93 assertTrue(lock.validate(stamp)); 94 return stamp; 95 } 96 assertUnlocked(StampedLock lock)97 void assertUnlocked(StampedLock lock) { 98 assertFalse(lock.isReadLocked()); 99 assertFalse(lock.isWriteLocked()); 100 assertEquals(0, lock.getReadLockCount()); 101 assertValid(lock, lock.tryOptimisticRead()); 102 } 103 lockLockers(Lock lock)104 List<Action> lockLockers(Lock lock) { 105 List<Action> lockers = new ArrayList<>(); 106 lockers.add(() -> lock.lock()); 107 lockers.add(() -> lock.lockInterruptibly()); 108 lockers.add(() -> lock.tryLock()); 109 lockers.add(() -> lock.tryLock(Long.MIN_VALUE, DAYS)); 110 lockers.add(() -> lock.tryLock(0L, DAYS)); 111 lockers.add(() -> lock.tryLock(Long.MAX_VALUE, DAYS)); 112 return lockers; 113 } 114 readLockers()115 List<Function<StampedLock, Long>> readLockers() { 116 List<Function<StampedLock, Long>> readLockers = new ArrayList<>(); 117 readLockers.add(sl -> sl.readLock()); 118 readLockers.add(sl -> sl.tryReadLock()); 119 readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl)); 120 readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS)); 121 readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS)); 122 readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead())); 123 return readLockers; 124 } 125 readUnlockers()126 List<BiConsumer<StampedLock, Long>> readUnlockers() { 127 List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>(); 128 readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp)); 129 readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead())); 130 readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock()); 131 readUnlockers.add((sl, stamp) -> sl.unlock(stamp)); 132 readUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp))); 133 return readUnlockers; 134 } 135 writeLockers()136 List<Function<StampedLock, Long>> writeLockers() { 137 List<Function<StampedLock, Long>> writeLockers = new ArrayList<>(); 138 writeLockers.add(sl -> sl.writeLock()); 139 writeLockers.add(sl -> sl.tryWriteLock()); 140 writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl)); 141 writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS)); 142 writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS)); 143 writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead())); 144 return writeLockers; 145 } 146 writeUnlockers()147 List<BiConsumer<StampedLock, Long>> writeUnlockers() { 148 List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>(); 149 writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp)); 150 writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite())); 151 writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock()); 152 writeUnlockers.add((sl, stamp) -> sl.unlock(stamp)); 153 writeUnlockers.add((sl, stamp) -> assertValid(sl, sl.tryConvertToOptimisticRead(stamp))); 154 return writeUnlockers; 155 } 156 157 /** 158 * Constructed StampedLock is in unlocked state 159 */ testConstructor()160 public void testConstructor() { 161 assertUnlocked(new StampedLock()); 162 } 163 164 /** 165 * write-locking, then unlocking, an unlocked lock succeed 166 */ testWriteLock_lockUnlock()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 */ testReadLock_lockUnlock()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 */ testTryUnlockWrite_failure()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 */ testTryUnlockRead_failure()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 */ testValidate0()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 */ testValidate()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 */ testValidate2()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 assertThrowInterruptedExceptionWhenPreInterrupted(Action[] actions)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 */ testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted()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 assertThrowInterruptedExceptionWhenInterrupted(Action[] actions)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 */ testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted()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 */ testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted()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 */ testNonInterruptibleOperationsIgnoreInterrupts()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 */ testTryWriteLock()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 */ testTryWriteLockWhenLocked()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 */ testTryReadLockWhenLocked()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 */ testMultipleReadLocks()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 */ testWriteAfterReadLock()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 */ testWriteAfterMultipleReadLocks()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 */ testReadAfterWriteLock()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 */ testTryLockWhenReadLocked()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 */ testTryWriteLockWhenReadLocked()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 */ testTimedLock_Timeout()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 */ testWriteLockInterruptibly()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 */ testReadLockInterruptibly()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 */ testSerialization()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 */ testToString()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 */ testValidateOptimistic()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 */ testValidateOptimisticWriteLocked()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 */ testValidateOptimisticWriteLocked2()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 */ testTryConvertToOptimisticRead()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 */ testTryConvertToReadLock()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 */ testTryConvertToWriteLock()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 */ testAsWriteLock()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 */ testAsReadLock()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 */ testAsReadWriteLockWriteLock()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 */ testAsReadWriteLockReadLock()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 */ testLockViewsDoNotSupportConditions()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 */ testCannotUnlockOptimisticReadStamps()1011 public void testCannotUnlockOptimisticReadStamps() { 1012 Runnable[] actions = { 1013 () -> { 1014 StampedLock sl = new StampedLock(); 1015 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1016 sl.unlockRead(stamp); 1017 }, 1018 () -> { 1019 StampedLock sl = new StampedLock(); 1020 long stamp = sl.tryOptimisticRead(); 1021 sl.unlock(stamp); 1022 }, 1023 1024 () -> { 1025 StampedLock sl = new StampedLock(); 1026 long stamp = sl.tryOptimisticRead(); 1027 sl.writeLock(); 1028 sl.unlock(stamp); 1029 }, 1030 () -> { 1031 StampedLock sl = new StampedLock(); 1032 sl.readLock(); 1033 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1034 sl.unlockRead(stamp); 1035 }, 1036 () -> { 1037 StampedLock sl = new StampedLock(); 1038 sl.readLock(); 1039 long stamp = assertValid(sl, sl.tryOptimisticRead()); 1040 sl.unlock(stamp); 1041 }, 1042 1043 () -> { 1044 StampedLock sl = new StampedLock(); 1045 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1046 assertValid(sl, stamp); 1047 sl.writeLock(); 1048 sl.unlockWrite(stamp); 1049 }, 1050 () -> { 1051 StampedLock sl = new StampedLock(); 1052 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1053 sl.writeLock(); 1054 sl.unlock(stamp); 1055 }, 1056 () -> { 1057 StampedLock sl = new StampedLock(); 1058 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1059 sl.readLock(); 1060 sl.unlockRead(stamp); 1061 }, 1062 () -> { 1063 StampedLock sl = new StampedLock(); 1064 long stamp = sl.tryConvertToOptimisticRead(sl.writeLock()); 1065 sl.readLock(); 1066 sl.unlock(stamp); 1067 }, 1068 1069 () -> { 1070 StampedLock sl = new StampedLock(); 1071 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1072 assertValid(sl, stamp); 1073 sl.writeLock(); 1074 sl.unlockWrite(stamp); 1075 }, 1076 () -> { 1077 StampedLock sl = new StampedLock(); 1078 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1079 sl.writeLock(); 1080 sl.unlock(stamp); 1081 }, 1082 () -> { 1083 StampedLock sl = new StampedLock(); 1084 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1085 sl.readLock(); 1086 sl.unlockRead(stamp); 1087 }, 1088 () -> { 1089 StampedLock sl = new StampedLock(); 1090 sl.readLock(); 1091 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1092 assertValid(sl, stamp); 1093 sl.readLock(); 1094 sl.unlockRead(stamp); 1095 }, 1096 () -> { 1097 StampedLock sl = new StampedLock(); 1098 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1099 sl.readLock(); 1100 sl.unlock(stamp); 1101 }, 1102 () -> { 1103 StampedLock sl = new StampedLock(); 1104 sl.readLock(); 1105 long stamp = sl.tryConvertToOptimisticRead(sl.readLock()); 1106 sl.readLock(); 1107 sl.unlock(stamp); 1108 }, 1109 }; 1110 1111 assertThrows(IllegalMonitorStateException.class, actions); 1112 } 1113 writeLockInterruptiblyUninterrupted(StampedLock sl)1114 static long writeLockInterruptiblyUninterrupted(StampedLock sl) { 1115 try { return sl.writeLockInterruptibly(); } 1116 catch (InterruptedException ex) { throw new AssertionError(ex); } 1117 } 1118 tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit)1119 static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1120 try { return sl.tryWriteLock(time, unit); } 1121 catch (InterruptedException ex) { throw new AssertionError(ex); } 1122 } 1123 readLockInterruptiblyUninterrupted(StampedLock sl)1124 static long readLockInterruptiblyUninterrupted(StampedLock sl) { 1125 try { return sl.readLockInterruptibly(); } 1126 catch (InterruptedException ex) { throw new AssertionError(ex); } 1127 } 1128 tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit)1129 static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) { 1130 try { return sl.tryReadLock(time, unit); } 1131 catch (InterruptedException ex) { throw new AssertionError(ex); } 1132 } 1133 1134 /** 1135 * Invalid stamps result in IllegalMonitorStateException 1136 */ testInvalidStampsThrowIllegalMonitorStateException()1137 public void testInvalidStampsThrowIllegalMonitorStateException() { 1138 final StampedLock sl = new StampedLock(); 1139 1140 assertThrows(IllegalMonitorStateException.class, 1141 () -> sl.unlockWrite(0L), 1142 () -> sl.unlockRead(0L), 1143 () -> sl.unlock(0L)); 1144 1145 final long optimisticStamp = sl.tryOptimisticRead(); 1146 final long readStamp = sl.readLock(); 1147 sl.unlockRead(readStamp); 1148 final long writeStamp = sl.writeLock(); 1149 sl.unlockWrite(writeStamp); 1150 assertTrue(optimisticStamp != 0L && readStamp != 0L && writeStamp != 0L); 1151 final long[] noLongerValidStamps = { optimisticStamp, readStamp, writeStamp }; 1152 final Runnable assertNoLongerValidStampsThrow = () -> { 1153 for (long noLongerValidStamp : noLongerValidStamps) 1154 assertThrows(IllegalMonitorStateException.class, 1155 () -> sl.unlockWrite(noLongerValidStamp), 1156 () -> sl.unlockRead(noLongerValidStamp), 1157 () -> sl.unlock(noLongerValidStamp)); 1158 }; 1159 assertNoLongerValidStampsThrow.run(); 1160 1161 for (Function<StampedLock, Long> readLocker : readLockers()) 1162 for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers()) { 1163 final long stamp = readLocker.apply(sl); 1164 assertValid(sl, stamp); 1165 assertNoLongerValidStampsThrow.run(); 1166 assertThrows(IllegalMonitorStateException.class, 1167 () -> sl.unlockWrite(stamp), 1168 () -> sl.unlockRead(sl.tryOptimisticRead()), 1169 () -> sl.unlockRead(0L)); 1170 readUnlocker.accept(sl, stamp); 1171 assertUnlocked(sl); 1172 assertNoLongerValidStampsThrow.run(); 1173 } 1174 1175 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1176 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1177 final long stamp = writeLocker.apply(sl); 1178 assertValid(sl, stamp); 1179 assertNoLongerValidStampsThrow.run(); 1180 assertThrows(IllegalMonitorStateException.class, 1181 () -> sl.unlockRead(stamp), 1182 () -> sl.unlockWrite(0L)); 1183 writeUnlocker.accept(sl, stamp); 1184 assertUnlocked(sl); 1185 assertNoLongerValidStampsThrow.run(); 1186 } 1187 } 1188 1189 /** 1190 * Read locks can be very deeply nested 1191 */ testDeeplyNestedReadLocks()1192 public void testDeeplyNestedReadLocks() { 1193 final StampedLock lock = new StampedLock(); 1194 final int depth = 300; 1195 final long[] stamps = new long[depth]; 1196 final List<Function<StampedLock, Long>> readLockers = readLockers(); 1197 final List<BiConsumer<StampedLock, Long>> readUnlockers = readUnlockers(); 1198 for (int i = 0; i < depth; i++) { 1199 Function<StampedLock, Long> readLocker 1200 = readLockers.get(i % readLockers.size()); 1201 long stamp = readLocker.apply(lock); 1202 assertEquals(i + 1, lock.getReadLockCount()); 1203 assertTrue(lock.isReadLocked()); 1204 stamps[i] = stamp; 1205 } 1206 for (int i = 0; i < depth; i++) { 1207 BiConsumer<StampedLock, Long> readUnlocker 1208 = readUnlockers.get(i % readUnlockers.size()); 1209 assertEquals(depth - i, lock.getReadLockCount()); 1210 assertTrue(lock.isReadLocked()); 1211 readUnlocker.accept(lock, stamps[depth - 1 - i]); 1212 } 1213 assertUnlocked(lock); 1214 } 1215 1216 /** 1217 * Stamped locks are not reentrant. 1218 */ testNonReentrant()1219 public void testNonReentrant() throws InterruptedException { 1220 final StampedLock lock = new StampedLock(); 1221 long stamp; 1222 1223 stamp = lock.writeLock(); 1224 assertValid(lock, stamp); 1225 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1226 assertEquals(0L, lock.tryReadLock(0L, DAYS)); 1227 assertValid(lock, stamp); 1228 lock.unlockWrite(stamp); 1229 1230 stamp = lock.tryWriteLock(1L, DAYS); 1231 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1232 assertValid(lock, stamp); 1233 lock.unlockWrite(stamp); 1234 1235 stamp = lock.readLock(); 1236 assertEquals(0L, lock.tryWriteLock(0L, DAYS)); 1237 assertValid(lock, stamp); 1238 lock.unlockRead(stamp); 1239 } 1240 1241 /** 1242 * """StampedLocks have no notion of ownership. Locks acquired in 1243 * one thread can be released or converted in another.""" 1244 */ testNoOwnership()1245 public void testNoOwnership() throws Throwable { 1246 ArrayList<Future<?>> futures = new ArrayList<>(); 1247 for (Function<StampedLock, Long> writeLocker : writeLockers()) 1248 for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) { 1249 StampedLock lock = new StampedLock(); 1250 long stamp = writeLocker.apply(lock); 1251 futures.add(cachedThreadPool.submit(new CheckedRunnable() { 1252 public void realRun() { 1253 writeUnlocker.accept(lock, stamp); 1254 assertUnlocked(lock); 1255 assertFalse(lock.validate(stamp)); 1256 }})); 1257 } 1258 for (Future<?> future : futures) 1259 assertNull(future.get()); 1260 } 1261 1262 /** Tries out sample usage code from StampedLock javadoc. */ testSampleUsage()1263 public void testSampleUsage() throws Throwable { 1264 class Point { 1265 private double x, y; 1266 private final StampedLock sl = new StampedLock(); 1267 1268 void move(double deltaX, double deltaY) { // an exclusively locked method 1269 long stamp = sl.writeLock(); 1270 try { 1271 x += deltaX; 1272 y += deltaY; 1273 } finally { 1274 sl.unlockWrite(stamp); 1275 } 1276 } 1277 1278 double distanceFromOrigin() { // A read-only method 1279 double currentX, currentY; 1280 long stamp = sl.tryOptimisticRead(); 1281 do { 1282 if (stamp == 0L) 1283 stamp = sl.readLock(); 1284 try { 1285 // possibly racy reads 1286 currentX = x; 1287 currentY = y; 1288 } finally { 1289 stamp = sl.tryConvertToOptimisticRead(stamp); 1290 } 1291 } while (stamp == 0); 1292 return Math.hypot(currentX, currentY); 1293 } 1294 1295 double distanceFromOrigin2() { 1296 long stamp = sl.tryOptimisticRead(); 1297 try { 1298 retryHoldingLock: 1299 for (;; stamp = sl.readLock()) { 1300 if (stamp == 0L) 1301 continue retryHoldingLock; 1302 // possibly racy reads 1303 double currentX = x; 1304 double currentY = y; 1305 if (!sl.validate(stamp)) 1306 continue retryHoldingLock; 1307 return Math.hypot(currentX, currentY); 1308 } 1309 } finally { 1310 if (StampedLock.isReadLockStamp(stamp)) 1311 sl.unlockRead(stamp); 1312 } 1313 } 1314 1315 void moveIfAtOrigin(double newX, double newY) { 1316 long stamp = sl.readLock(); 1317 try { 1318 while (x == 0.0 && y == 0.0) { 1319 long ws = sl.tryConvertToWriteLock(stamp); 1320 if (ws != 0L) { 1321 stamp = ws; 1322 x = newX; 1323 y = newY; 1324 return; 1325 } 1326 else { 1327 sl.unlockRead(stamp); 1328 stamp = sl.writeLock(); 1329 } 1330 } 1331 } finally { 1332 sl.unlock(stamp); 1333 } 1334 } 1335 } 1336 1337 Point p = new Point(); 1338 p.move(3.0, 4.0); 1339 assertEquals(5.0, p.distanceFromOrigin()); 1340 p.moveIfAtOrigin(5.0, 12.0); 1341 assertEquals(5.0, p.distanceFromOrigin2()); 1342 } 1343 1344 /** 1345 * Stamp inspection methods work as expected, and do not inspect 1346 * the state of the lock itself. 1347 */ testStampStateInspectionMethods()1348 public void testStampStateInspectionMethods() { 1349 StampedLock lock = new StampedLock(); 1350 1351 assertFalse(isWriteLockStamp(0L)); 1352 assertFalse(isReadLockStamp(0L)); 1353 assertFalse(isLockStamp(0L)); 1354 assertFalse(isOptimisticReadStamp(0L)); 1355 1356 { 1357 long stamp = lock.writeLock(); 1358 for (int i = 0; i < 2; i++) { 1359 assertTrue(isWriteLockStamp(stamp)); 1360 assertFalse(isReadLockStamp(stamp)); 1361 assertTrue(isLockStamp(stamp)); 1362 assertFalse(isOptimisticReadStamp(stamp)); 1363 if (i == 0) 1364 lock.unlockWrite(stamp); 1365 } 1366 } 1367 1368 { 1369 long stamp = lock.readLock(); 1370 for (int i = 0; i < 2; i++) { 1371 assertFalse(isWriteLockStamp(stamp)); 1372 assertTrue(isReadLockStamp(stamp)); 1373 assertTrue(isLockStamp(stamp)); 1374 assertFalse(isOptimisticReadStamp(stamp)); 1375 if (i == 0) 1376 lock.unlockRead(stamp); 1377 } 1378 } 1379 1380 { 1381 long optimisticStamp = lock.tryOptimisticRead(); 1382 long readStamp = lock.tryConvertToReadLock(optimisticStamp); 1383 long writeStamp = lock.tryConvertToWriteLock(readStamp); 1384 for (int i = 0; i < 2; i++) { 1385 assertFalse(isWriteLockStamp(optimisticStamp)); 1386 assertFalse(isReadLockStamp(optimisticStamp)); 1387 assertFalse(isLockStamp(optimisticStamp)); 1388 assertTrue(isOptimisticReadStamp(optimisticStamp)); 1389 1390 assertFalse(isWriteLockStamp(readStamp)); 1391 assertTrue(isReadLockStamp(readStamp)); 1392 assertTrue(isLockStamp(readStamp)); 1393 assertFalse(isOptimisticReadStamp(readStamp)); 1394 1395 assertTrue(isWriteLockStamp(writeStamp)); 1396 assertFalse(isReadLockStamp(writeStamp)); 1397 assertTrue(isLockStamp(writeStamp)); 1398 assertFalse(isOptimisticReadStamp(writeStamp)); 1399 if (i == 0) 1400 lock.unlockWrite(writeStamp); 1401 } 1402 } 1403 } 1404 1405 } 1406