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 }