8229442: AQS and lock classes refresh
authordl
Sat, 14 Sep 2019 11:16:40 -0700
changeset 58134 51cd29502ea9
parent 58133 515fc9f6b2d6
child 58135 2081ff900d65
8229442: AQS and lock classes refresh Reviewed-by: martin
src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
src/java.base/share/classes/java/util/concurrent/locks/Lock.java
src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java
src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java
src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java
test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java
test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java
test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java
test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java
test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java
test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java
test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java
test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Sat Sep 14 11:16:40 2019 -0700
@@ -35,13 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A version of {@link AbstractQueuedSynchronizer} in
@@ -73,23 +72,76 @@
      * keep it that way.
      */
 
-    /**
-     * Creates a new {@code AbstractQueuedLongSynchronizer} instance
-     * with initial synchronization state of zero.
-     */
-    protected AbstractQueuedLongSynchronizer() { }
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
+
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
+
+        /**
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
+         */
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
+        }
+    }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -113,8 +165,7 @@
      * @param newState the new state value
      */
     protected final void setState(long newState) {
-        // See JDK-8180620: Clarify VarHandle mixed-access subtleties
-        STATE.setVolatile(this, newState);
+        state = newState;
     }
 
     /**
@@ -129,481 +180,234 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(long expect, long update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetLong(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, long arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, long propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, long arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(long arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -756,9 +560,8 @@
      *        can represent anything you like.
      */
     public final void acquire(long arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -776,11 +579,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -801,11 +603,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -820,9 +631,7 @@
      */
     public final boolean release(long arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -841,7 +650,7 @@
      */
     public final void acquireShared(long arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -858,11 +667,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -883,10 +692,19 @@
      */
     public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -900,7 +718,7 @@
      */
     public final boolean releaseShared(long arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -918,7 +736,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -948,45 +766,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1003,7 +792,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1019,10 +808,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1052,7 +839,7 @@
      * synchronizer might look like this:
      *
      * <pre> {@code
-     * protected boolean tryAcquire(int arg) {
+     * protected boolean tryAcquire(long arg) {
      *   if (isHeldExclusively()) {
      *     // A reentrant acquire; increment hold count
      *     return true;
@@ -1069,19 +856,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1098,7 +878,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1118,7 +898,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1136,8 +916,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1156,8 +936,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1180,117 +960,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final long fullyRelease(Node node) {
-        try {
-            long savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1384,112 +1053,38 @@
      *
      * <p>This class is Serializable, but all fields are transient,
      * so deserialized conditions have no waiters.
-     *
-     * @since 1.6
      */
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1499,11 +1094,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1514,11 +1109,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private long enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                long savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -1533,51 +1189,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -1596,20 +1228,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -1629,32 +1274,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -1676,26 +1318,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -1717,31 +1359,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -1767,8 +1406,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -1787,8 +1426,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -1807,9 +1446,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -1818,39 +1457,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
-            HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Sat Sep 14 11:16:40 2019 -0700
@@ -35,12 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * Provides a framework for implementing blocking locks and related
@@ -312,265 +312,208 @@
      */
     protected AbstractQueuedSynchronizer() { }
 
-    /**
-     * Wait queue node class.
+    /*
+     * Overview.
      *
-     * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * The wait queue is a variant of a "CLH" (Craig, Landin, and
      * Hagersten) lock queue. CLH locks are normally used for
-     * spinlocks.  We instead use them for blocking synchronizers, but
-     * use the same basic tactic of holding some of the control
-     * information about a thread in the predecessor of its node.  A
-     * "status" field in each node keeps track of whether a thread
-     * should block.  A node is signalled when its predecessor
-     * releases.  Each node of the queue otherwise serves as a
-     * specific-notification-style monitor holding a single waiting
-     * thread. The status field does NOT control whether threads are
-     * granted locks etc though.  A thread may try to acquire if it is
-     * first in the queue. But being first does not guarantee success;
-     * it only gives the right to contend.  So the currently released
-     * contender thread may need to rewait.
+     * spinlocks.  We instead use them for blocking synchronizers by
+     * including explicit ("prev" and "next") links plus a "status"
+     * field that allow nodes to signal successors when releasing
+     * locks, and handle cancellation due to interrupts and timeouts.
+     * The status field includes bits that track whether a thread
+     * needs a signal (using LockSupport.unpark). Despite these
+     * additions, we maintain most CLH locality properties.
+     *
+     * To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you set the head field, so the next eligible
+     * waiter becomes first.
      *
-     * <p>To enqueue into a CLH lock, you atomically splice it in as new
-     * tail. To dequeue, you just set the head field.
-     * <pre>
-     *      +------+  prev +-----+       +-----+
-     * head |      | <---- |     | <---- |     |  tail
-     *      +------+       +-----+       +-----+
-     * </pre>
+     *  +------+  prev +-------+       +------+
+     *  | head | <---- | first | <---- | tail |
+     *  +------+       +-------+       +------+
+     *
+     * Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple point of demarcation
+     * from unqueued to queued. The "next" link of the predecessor is
+     * set by the enqueuing thread after successful CAS. Even though
+     * non-atomic, this suffices to ensure that any blocked thread is
+     * signalled by a predecessor when eligible (although in the case
+     * of cancellation, possibly with the assistance of a signal in
+     * method cleanQueue). Signalling is based in part on a
+     * Dekker-like scheme in which the to-be waiting thread indicates
+     * WAITING status, then retries acquiring, and then rechecks
+     * status before blocking. The signaller atomically clears WAITING
+     * status when unparking.
      *
-     * <p>Insertion into a CLH queue requires only a single atomic
-     * operation on "tail", so there is a simple atomic point of
-     * demarcation from unqueued to queued. Similarly, dequeuing
-     * involves only updating the "head". However, it takes a bit
-     * more work for nodes to determine who their successors are,
-     * in part to deal with possible cancellation due to timeouts
-     * and interrupts.
-     *
-     * <p>The "prev" links (not used in original CLH locks), are mainly
-     * needed to handle cancellation. If a node is cancelled, its
-     * successor is (normally) relinked to a non-cancelled
-     * predecessor. For explanation of similar mechanics in the case
-     * of spin locks, see the papers by Scott and Scherer at
-     * http://www.cs.rochester.edu/u/scott/synchronization/
+     * Dequeuing on acquire involves detaching (nulling) a node's
+     * "prev" node and then updating the "head". Other threads check
+     * if a node is or was dequeued by checking "prev" rather than
+     * head. We enforce the nulling then setting order by spin-waiting
+     * if necessary. Because of this, the lock algorithm is not itself
+     * strictly "lock-free" because an acquiring thread may need to
+     * wait for a previous acquire to make progress. When used with
+     * exclusive locks, such progress is required anyway. However
+     * Shared mode may (uncommonly) require a spin-wait before
+     * setting head field to ensure proper propagation. (Historical
+     * note: This allows some simplifications and efficiencies
+     * compared to previous versions of this class.)
      *
-     * <p>We also use "next" links to implement blocking mechanics.
-     * The thread id for each node is kept in its own node, so a
-     * predecessor signals the next node to wake up by traversing
-     * next link to determine which thread it is.  Determination of
-     * successor must avoid races with newly queued nodes to set
-     * the "next" fields of their predecessors.  This is solved
-     * when necessary by checking backwards from the atomically
-     * updated "tail" when a node's successor appears to be null.
-     * (Or, said differently, the next-links are an optimization
-     * so that we don't usually need a backward scan.)
+     * A node's predecessor can change due to cancellation while it is
+     * waiting, until the node is first in queue, at which point it
+     * cannot change. The acquire methods cope with this by rechecking
+     * "prev" before waiting. The prev and next fields are modified
+     * only via CAS by cancelled nodes in method cleanQueue. The
+     * unsplice strategy is reminiscent of Michael-Scott queues in
+     * that after a successful CAS to prev field, other threads help
+     * fix next fields.  Because cancellation often occurs in bunches
+     * that complicate decisions about necessary signals, each call to
+     * cleanQueue traverses the queue until a clean sweep. Nodes that
+     * become relinked as first are unconditionally unparked
+     * (sometimes unnecessarily, but those cases are not worth
+     * avoiding).
      *
-     * <p>Cancellation introduces some conservatism to the basic
-     * algorithms.  Since we must poll for cancellation of other
-     * nodes, we can miss noticing whether a cancelled node is
-     * ahead or behind us. This is dealt with by always unparking
-     * successors upon cancellation, allowing them to stabilize on
-     * a new predecessor, unless we can identify an uncancelled
-     * predecessor who will carry this responsibility.
+     * A thread may try to acquire if it is first (frontmost) in the
+     * queue, and sometimes before.  Being first does not guarantee
+     * success; it only gives the right to contend. We balance
+     * throughput, overhead, and fairness by allowing incoming threads
+     * to "barge" and acquire the synchronizer while in the process of
+     * enqueuing, in which case an awakened first thread may need to
+     * rewait.  To counteract possible repeated unlucky rewaits, we
+     * exponentially increase retries (up to 256) to acquire each time
+     * a thread is unparked. Except in this case, AQS locks do not
+     * spin; they instead interleave attempts to acquire with
+     * bookkeeping steps. (Users who want spinlocks can use
+     * tryAcquire.)
      *
-     * <p>CLH queues need a dummy header node to get started. But
+     * To improve garbage collectibility, fields of nodes not yet on
+     * list are null. (It is not rare to create and then throw away a
+     * node without using it.) Fields of nodes coming off the list are
+     * nulled out as soon as possible. This accentuates the challenge
+     * of externally determining the first waiting thread (as in
+     * method getFirstQueuedThread). This sometimes requires the
+     * fallback of traversing backwards from the atomically updated
+     * "tail" when fields appear null. (This is never needed in the
+     * process of signalling though.)
+     *
+     * CLH queues need a dummy header node to get started. But
      * we don't create them on construction, because it would be wasted
      * effort if there is never contention. Instead, the node
      * is constructed and head and tail pointers are set upon first
      * contention.
      *
-     * <p>Threads waiting on Conditions use the same nodes, but
-     * use an additional link. Conditions only need to link nodes
-     * in simple (non-concurrent) linked queues because they are
-     * only accessed when exclusively held.  Upon await, a node is
-     * inserted into a condition queue.  Upon signal, the node is
-     * transferred to the main queue.  A special value of status
-     * field is used to mark which queue a node is on.
+     * Shared mode operations differ from Exclusive in that an acquire
+     * signals the next waiter to try to acquire if it is also
+     * Shared. The tryAcquireShared API allows users to indicate the
+     * degree of propagation, but in most applications, it is more
+     * efficient to ignore this, allowing the successor to try
+     * acquiring in any case.
+     *
+     * Threads waiting on Conditions use nodes with an additional
+     * link to maintain the (FIFO) list of conditions. Conditions only
+     * need to link nodes in simple (non-concurrent) linked queues
+     * because they are only accessed when exclusively held.  Upon
+     * await, a node is inserted into a condition queue.  Upon signal,
+     * the node is enqueued on the main queue.  A special status field
+     * value is used to track and atomically trigger this.
      *
-     * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Accesses to fields head, tail, and state use full Volatile
+     * mode, along with CAS. Node fields status, prev and next also do
+     * so while threads may be signallable, but sometimes use weaker
+     * modes otherwise. Accesses to field "waiter" (the thread to be
+     * signalled) are always sandwiched between other atomic accesses
+     * so are used in Plain mode. We use jdk.internal Unsafe versions
+     * of atomic access methods rather than VarHandles to avoid
+     * potential VM bootstrap issues.
+     *
+     * Most of the above is performed by primary internal method
+     * acquire, that is invoked in some way by all exported acquire
+     * methods.  (It is usually easy for compilers to optimize
+     * call-site specializations when heavily used.)
+     *
+     * There are several arbitrary decisions about when and how to
+     * check interrupts in both acquire and await before and/or after
+     * blocking. The decisions are less arbitrary in implementation
+     * updates because some users appear to rely on original behaviors
+     * in ways that are racy and so (rarely) wrong in general but hard
+     * to justify changing.
+     *
+     * Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
      * Scherer and Michael Scott, along with members of JSR-166
      * expert group, for helpful ideas, discussions, and critiques
      * on the design of this class.
      */
-    static final class Node {
-        /** Marker to indicate a node is waiting in shared mode */
-        static final Node SHARED = new Node();
-        /** Marker to indicate a node is waiting in exclusive mode */
-        static final Node EXCLUSIVE = null;
+
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
 
-        /** waitStatus value to indicate thread has cancelled. */
-        static final int CANCELLED =  1;
-        /** waitStatus value to indicate successor's thread needs unparking. */
-        static final int SIGNAL    = -1;
-        /** waitStatus value to indicate thread is waiting on condition. */
-        static final int CONDITION = -2;
-        /**
-         * waitStatus value to indicate the next acquireShared should
-         * unconditionally propagate.
-         */
-        static final int PROPAGATE = -3;
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-        /**
-         * Status field, taking on only the values:
-         *   SIGNAL:     The successor of this node is (or will soon be)
-         *               blocked (via park), so the current node must
-         *               unpark its successor when it releases or
-         *               cancels. To avoid races, acquire methods must
-         *               first indicate they need a signal,
-         *               then retry the atomic acquire, and then,
-         *               on failure, block.
-         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
-         *               Nodes never leave this state. In particular,
-         *               a thread with cancelled node never again blocks.
-         *   CONDITION:  This node is currently on a condition queue.
-         *               It will not be used as a sync queue node
-         *               until transferred, at which time the status
-         *               will be set to 0. (Use of this value here has
-         *               nothing to do with the other uses of the
-         *               field, but simplifies mechanics.)
-         *   PROPAGATE:  A releaseShared should be propagated to other
-         *               nodes. This is set (for head node only) in
-         *               doReleaseShared to ensure propagation
-         *               continues, even if other operations have
-         *               since intervened.
-         *   0:          None of the above
-         *
-         * The values are arranged numerically to simplify use.
-         * Non-negative values mean that a node doesn't need to
-         * signal. So, most code doesn't need to check for particular
-         * values, just for sign.
-         *
-         * The field is initialized to 0 for normal sync nodes, and
-         * CONDITION for condition nodes.  It is modified using CAS
-         * (or when possible, unconditional volatile writes).
-         */
-        volatile int waitStatus;
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
 
-        /**
-         * Link to predecessor node that current node/thread relies on
-         * for checking waitStatus. Assigned during enqueuing, and nulled
-         * out (for sake of GC) only upon dequeuing.  Also, upon
-         * cancellation of a predecessor, we short-circuit while
-         * finding a non-cancelled one, which will always exist
-         * because the head node is never cancelled: A node becomes
-         * head only as a result of successful acquire. A
-         * cancelled thread never succeeds in acquiring, and a thread only
-         * cancels itself, not any other node.
-         */
-        volatile Node prev;
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
 
-        /**
-         * Link to the successor node that the current node/thread
-         * unparks upon release. Assigned during enqueuing, adjusted
-         * when bypassing cancelled predecessors, and nulled out (for
-         * sake of GC) when dequeued.  The enq operation does not
-         * assign next field of a predecessor until after attachment,
-         * so seeing a null next field does not necessarily mean that
-         * node is at end of queue. However, if a next field appears
-         * to be null, we can scan prev's from the tail to
-         * double-check.  The next field of cancelled nodes is set to
-         * point to the node itself instead of null, to make life
-         * easier for isOnSyncQueue.
-         */
-        volatile Node next;
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
 
         /**
-         * The thread that enqueued this node.  Initialized on
-         * construction and nulled out after use.
-         */
-        volatile Thread thread;
-
-        /**
-         * Link to next node waiting on condition, or the special
-         * value SHARED.  Because condition queues are accessed only
-         * when holding in exclusive mode, we just need a simple
-         * linked queue to hold nodes while they are waiting on
-         * conditions. They are then transferred to the queue to
-         * re-acquire. And because conditions can only be exclusive,
-         * we save a field by using special value to indicate shared
-         * mode.
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
          */
-        Node nextWaiter;
-
-        /**
-         * Returns true if node is waiting in shared mode.
-         */
-        final boolean isShared() {
-            return nextWaiter == SHARED;
-        }
-
-        /**
-         * Returns previous node, or throws NullPointerException if null.
-         * Use when predecessor cannot be null.  The null check could
-         * be elided, but is present to help the VM.
-         *
-         * @return the predecessor of this node
-         */
-        final Node predecessor() {
-            Node p = prev;
-            if (p == null)
-                throw new NullPointerException();
-            else
-                return p;
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
         }
 
-        /** Establishes initial head or SHARED marker. */
-        Node() {}
-
-        /** Constructor used by addWaiter. */
-        Node(Node nextWaiter) {
-            this.nextWaiter = nextWaiter;
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** Constructor used by addConditionWaiter. */
-        Node(int waitStatus) {
-            WAITSTATUS.set(this, waitStatus);
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** CASes waitStatus field. */
-        final boolean compareAndSetWaitStatus(int expect, int update) {
-            return WAITSTATUS.compareAndSet(this, expect, update);
-        }
-
-        /** CASes next field. */
-        final boolean compareAndSetNext(Node expect, Node update) {
-            return NEXT.compareAndSet(this, expect, update);
-        }
-
-        final void setPrevRelaxed(Node p) {
-            PREV.set(this, p);
-        }
-
-        // VarHandle mechanics
-        private static final VarHandle NEXT;
-        private static final VarHandle PREV;
-        private static final VarHandle THREAD;
-        private static final VarHandle WAITSTATUS;
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                NEXT = l.findVarHandle(Node.class, "next", Node.class);
-                PREV = l.findVarHandle(Node.class, "prev", Node.class);
-                THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
-                WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
-            } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
-            }
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
         }
     }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -609,481 +552,235 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(int expect, int update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetInt(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, int arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, int propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, int arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(int arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -1236,9 +933,8 @@
      *        can represent anything you like.
      */
     public final void acquire(int arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -1256,11 +952,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -1281,11 +976,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1300,9 +1004,7 @@
      */
     public final boolean release(int arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -1321,7 +1023,7 @@
      */
     public final void acquireShared(int arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -1338,11 +1040,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -1363,10 +1065,19 @@
      */
     public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1380,7 +1091,7 @@
      */
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -1398,7 +1109,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -1428,45 +1139,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1483,7 +1165,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1499,10 +1181,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1549,19 +1229,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1578,7 +1251,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1598,7 +1271,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1616,8 +1289,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1636,8 +1309,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1660,117 +1333,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final int fullyRelease(Node node) {
-        try {
-            int savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1868,106 +1430,34 @@
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1977,11 +1467,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1992,11 +1482,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private int enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                int savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -2011,51 +1562,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -2074,20 +1601,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -2107,32 +1647,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -2154,26 +1691,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -2195,31 +1732,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -2245,8 +1779,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -2265,8 +1799,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -2285,9 +1819,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -2296,39 +1830,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
-            HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Sat Sep 14 11:16:40 2019 -0700
@@ -122,9 +122,8 @@
  * <p>All {@code Lock} implementations <em>must</em> enforce the same
  * memory synchronization semantics as provided by the built-in monitor
  * lock, as described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
  * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a>:
+ * <cite>The Java&trade; Language Specification</cite>:
  * <ul>
  * <li>A successful {@code lock} operation has the same memory
  * synchronization effects as a successful <em>Lock</em> action.
@@ -162,6 +161,7 @@
  * @see ReentrantLock
  * @see Condition
  * @see ReadWriteLock
+ * @jls 17.4 Memory Model
  *
  * @since 1.5
  * @author Doug Lea
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Sat Sep 14 11:16:40 2019 -0700
@@ -140,8 +140,25 @@
     private LockSupport() {} // Cannot be instantiated.
 
     private static void setBlocker(Thread t, Object arg) {
-        // Even though volatile, hotspot doesn't need a write barrier here.
-        U.putReference(t, PARKBLOCKER, arg);
+        U.putReferenceOpaque(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Sets the object to be returned by invocations of {@link
+     * #getBlocker getBlocker} for the current thread. This method may
+     * be used before invoking the no-argument version of {@link
+     * LockSupport#park() park()} from non-public objects, allowing
+     * more helpful diagnostics, or retaining compatibility with
+     * previous implementations of blocking methods.  Previous values
+     * of the blocker are not automatically restored after blocking.
+     * To obtain the effects of {@code park(b}}, use {@code
+     * setCurrentBlocker(b); park(); setCurrentBlocker(null);}
+     *
+     * @param blocker the blocker object
+     * @since 14
+     */
+    public static void setCurrentBlocker(Object blocker) {
+        U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
     }
 
     /**
@@ -292,7 +309,7 @@
     public static Object getBlocker(Thread t) {
         if (t == null)
             throw new NullPointerException();
-        return U.getReferenceVolatile(t, PARKBLOCKER);
+        return U.getReferenceOpaque(t, PARKBLOCKER);
     }
 
     /**
@@ -394,24 +411,6 @@
     }
 
     /**
-     * Returns the pseudo-randomly initialized or updated secondary seed.
-     * Copied from ThreadLocalRandom due to package access restrictions.
-     */
-    static final int nextSecondarySeed() {
-        int r;
-        Thread t = Thread.currentThread();
-        if ((r = U.getInt(t, SECONDARY)) != 0) {
-            r ^= r << 13;   // xorshift
-            r ^= r >>> 17;
-            r ^= r << 5;
-        }
-        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
-            r = 1; // avoid zero
-        U.putInt(t, SECONDARY, r);
-        return r;
-    }
-
-    /**
      * Returns the thread id for the given thread.  We must access
      * this directly rather than via method Thread.getId() because
      * getId() has been known to be overridden in ways that do not
@@ -423,11 +422,9 @@
 
     // Hotspot implementation via intrinsics API
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long PARKBLOCKER = U.objectFieldOffset
-            (Thread.class, "parkBlocker");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long TID = U.objectFieldOffset
-            (Thread.class, "tid");
+    private static final long PARKBLOCKER
+        = U.objectFieldOffset(Thread.class, "parkBlocker");
+    private static final long TID
+        = U.objectFieldOffset(Thread.class, "tid");
 
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Sat Sep 14 11:16:40 2019 -0700
@@ -119,39 +119,63 @@
         private static final long serialVersionUID = -5179523762034025860L;
 
         /**
-         * Performs non-fair tryLock.  tryAcquire is implemented in
-         * subclasses, but both need nonfair try for trylock method.
+         * Performs non-fair tryLock.
          */
         @ReservedStackAccess
-        final boolean nonfairTryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean tryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (compareAndSetState(0, acquires)) {
+                if (compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
-            }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0) // overflow
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
                     throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+                setState(c);
                 return true;
             }
             return false;
         }
 
+        /**
+         * Checks for reentrancy and acquires if lock immediately
+         * available under fair vs nonfair rules. Locking methods
+         * perform initialTryLock check before relaying to
+         * corresponding AQS acquire methods.
+         */
+        abstract boolean initialTryLock();
+
+        @ReservedStackAccess
+        final void lock() {
+            if (!initialTryLock())
+                acquire(1);
+        }
+
+        @ReservedStackAccess
+        final void lockInterruptibly() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            if (!initialTryLock())
+                acquireInterruptibly(1);
+        }
+
+        @ReservedStackAccess
+        final boolean tryLockNanos(long nanos) throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            return initialTryLock() || tryAcquireNanos(1, nanos);
+        }
+
         @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             int c = getState() - releases;
-            if (Thread.currentThread() != getExclusiveOwnerThread())
+            if (getExclusiveOwnerThread() != Thread.currentThread())
                 throw new IllegalMonitorStateException();
-            boolean free = false;
-            if (c == 0) {
-                free = true;
+            boolean free = (c == 0);
+            if (free)
                 setExclusiveOwnerThread(null);
-            }
             setState(c);
             return free;
         }
@@ -195,8 +219,31 @@
      */
     static final class NonfairSync extends Sync {
         private static final long serialVersionUID = 7316153563782823691L;
+
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
+            if (compareAndSetState(0, 1)) { // first attempt is unguarded
+                setExclusiveOwnerThread(current);
+                return true;
+            } else if (getExclusiveOwnerThread() == current) {
+                int c = getState() + 1;
+                if (c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            } else
+                return false;
+        }
+
+        /**
+         * Acquire for non-reentrant cases after initialTryLock prescreen
+         */
         protected final boolean tryAcquire(int acquires) {
-            return nonfairTryAcquire(acquires);
+            if (getState() == 0 && compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
         }
     }
 
@@ -205,26 +252,34 @@
      */
     static final class FairSync extends Sync {
         private static final long serialVersionUID = -3000897897090466540L;
+
         /**
-         * Fair version of tryAcquire.  Don't grant access unless
-         * recursive call or no waiters or is first.
+         * Acquires only if reentrant or queue is empty.
          */
-        @ReservedStackAccess
-        protected final boolean tryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (!hasQueuedPredecessors() &&
-                    compareAndSetState(0, acquires)) {
+                if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
             }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0)
-                    throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+            return false;
+        }
+
+        /**
+         * Acquires only if thread is first waiter or empty
+         */
+        protected final boolean tryAcquire(int acquires) {
+            if (getState() == 0 && !hasQueuedPredecessors() &&
+                compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
                 return true;
             }
             return false;
@@ -264,7 +319,7 @@
      * at which time the lock hold count is set to one.
      */
     public void lock() {
-        sync.acquire(1);
+        sync.lock();
     }
 
     /**
@@ -314,7 +369,7 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public void lockInterruptibly() throws InterruptedException {
-        sync.acquireInterruptibly(1);
+        sync.lockInterruptibly();
     }
 
     /**
@@ -344,7 +399,7 @@
      *         thread; and {@code false} otherwise
      */
     public boolean tryLock() {
-        return sync.nonfairTryAcquire(1);
+        return sync.tryLock();
     }
 
     /**
@@ -421,7 +476,7 @@
      */
     public boolean tryLock(long timeout, TimeUnit unit)
             throws InterruptedException {
-        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        return sync.tryLockNanos(unit.toNanos(timeout));
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Sat Sep 14 11:16:40 2019 -0700
@@ -35,9 +35,8 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
@@ -132,9 +131,8 @@
  *
  * <p><b>Memory Synchronization.</b> Methods with the effect of
  * successfully locking in any mode have the same memory
- * synchronization effects as a <em>Lock</em> action described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
- * Chapter 17 of <cite>The Java&trade; Language Specification</cite></a>.
+ * synchronization effects as a <em>Lock</em> action, as described in
+ * Chapter 17 of <cite>The Java&trade; Language Specification</cite>.
  * Methods successfully unlocking in write mode have the same memory
  * synchronization effects as an <em>Unlock</em> action.  In optimistic
  * read usages, actions prior to the most recent write mode unlock action
@@ -237,6 +235,7 @@
  *   }
  * }}</pre>
  *
+ * @jls 17.4 Memory Model
  * @since 1.8
  * @author Doug Lea
  */
@@ -264,122 +263,54 @@
      * updates.
      *
      * Waiters use a modified form of CLH lock used in
-     * AbstractQueuedSynchronizer (see its internal documentation for
-     * a fuller account), where each node is tagged (field mode) as
-     * either a reader or writer. Sets of waiting readers are grouped
-     * (linked) under a common node (field cowait) so act as a single
-     * node with respect to most CLH mechanics.  By virtue of the
-     * queue structure, wait nodes need not actually carry sequence
-     * numbers; we know each is greater than its predecessor.  This
-     * simplifies the scheduling policy to a mainly-FIFO scheme that
-     * incorporates elements of Phase-Fair locks (see Brandenburg &
-     * Anderson, especially http://www.cs.unc.edu/~bbb/diss/).  In
-     * particular, we use the phase-fair anti-barging rule: If an
-     * incoming reader arrives while read lock is held but there is a
-     * queued writer, this incoming reader is queued.  (This rule is
-     * responsible for some of the complexity of method acquireRead,
-     * but without it, the lock becomes highly unfair.) Method release
-     * does not (and sometimes cannot) itself wake up cowaiters. This
-     * is done by the primary thread, but helped by any other threads
-     * with nothing better to do in methods acquireRead and
-     * acquireWrite.
+     * AbstractQueuedSynchronizer (AQS; see its internal documentation
+     * for a fuller account), where each node is either a ReaderNode
+     * or WriterNode. Implementation of queued Writer mode is
+     * identical to AQS except for lock-state operations.  Sets of
+     * waiting readers are grouped (linked) under a common node (field
+     * cowaiters) so act as a single node with respect to most CLH
+     * mechanics.  This simplifies the scheduling policy to a
+     * mainly-FIFO scheme that incorporates elements of Phase-Fair
+     * locks (see Brandenburg & Anderson, especially
+     * http://www.cs.unc.edu/~bbb/diss/).  Method release does not
+     * itself wake up cowaiters. This is done by the primary thread,
+     * but helped by other cowaiters as they awaken.
      *
-     * These rules apply to threads actually queued. All tryLock forms
-     * opportunistically try to acquire locks regardless of preference
-     * rules, and so may "barge" their way in.  Randomized spinning is
-     * used in the acquire methods to reduce (increasingly expensive)
-     * context switching while also avoiding sustained memory
-     * thrashing among many threads.  We limit spins to the head of
-     * queue. If, upon wakening, a thread fails to obtain lock, and is
-     * still (or becomes) the first waiting thread (which indicates
-     * that some other thread barged and obtained lock), it escalates
-     * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
-     * continually losing to barging threads.
+     * These rules apply to threads actually queued. Threads may also
+     * try to acquire locks before or in the process of enqueueing
+     * regardless of preference rules, and so may "barge" their way
+     * in.  Methods writeLock and readLock (but not the other variants
+     * of each) first unconditionally try to CAS state, falling back
+     * to test-and-test-and-set retries on failure, slightly shrinking
+     * race windows on initial attempts, thus making success more
+     * likely. Also, when some threads cancel (via interrupt or
+     * timeout), phase-fairness is at best roughly approximated.
      *
      * Nearly all of these mechanics are carried out in methods
      * acquireWrite and acquireRead, that, as typical of such code,
      * sprawl out because actions and retries rely on consistent sets
      * of locally cached reads.
      *
-     * As noted in Boehm's paper (above), sequence validation (mainly
-     * method validate()) requires stricter ordering rules than apply
-     * to normal volatile reads (of "state").  To force orderings of
-     * reads before a validation and the validation itself in those
-     * cases where this is not already forced, we use acquireFence.
-     * Unlike in that paper, we allow writers to use plain writes.
-     * One would not expect reorderings of such writes with the lock
-     * acquisition CAS because there is a "control dependency", but it
-     * is theoretically possible, so we additionally add a
-     * storeStoreFence after lock acquisition CAS.
-     *
-     * ----------------------------------------------------------------
-     * Here's an informal proof that plain reads by _successful_
-     * readers see plain writes from preceding but not following
-     * writers (following Boehm and the C++ standard [atomics.fences]):
-     *
-     * Because of the total synchronization order of accesses to
-     * volatile long state containing the sequence number, writers and
-     * _successful_ readers can be globally sequenced.
-     *
-     * int x, y;
-     *
-     * Writer 1:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 1; y = 2;
-     * inc sequence (even - "unlocked")
-     *
-     * Successful Reader:
-     * read sequence (even)
-     * // must see writes from Writer 1 but not Writer 2
-     * r1 = x; r2 = y;
-     * acquireFence();
-     * read sequence (even - validated unchanged)
-     * // use r1 and r2
-     *
-     * Writer 2:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 3; y = 4;
-     * inc sequence (even - "unlocked")
-     *
-     * Visibility of writer 1's stores is normal - reader's initial
-     * read of state synchronizes with writer 1's final write to state.
-     * Lack of visibility of writer 2's plain writes is less obvious.
-     * If reader's read of x or y saw writer 2's write, then (assuming
-     * semantics of C++ fences) the storeStoreFence would "synchronize"
-     * with reader's acquireFence and reader's validation read must see
-     * writer 2's initial write to state and so validation must fail.
-     * But making this "proof" formal and rigorous is an open problem!
-     * ----------------------------------------------------------------
+     * For an explanation of the use of acquireFence, see
+     * http://gee.cs.oswego.edu/dl/html/j9mm.html as well as Boehm's
+     * paper (above). Note that sequence validation (mainly method
+     * validate()) requires stricter ordering rules than apply to
+     * normal volatile reads (of "state").  To ensure that writeLock
+     * acquisitions strictly precede subsequent writes in cases where
+     * this is not already forced, we use a storeStoreFence.
      *
      * The memory layout keeps lock state and queue pointers together
      * (normally on the same cache line). This usually works well for
      * read-mostly loads. In most other cases, the natural tendency of
-     * adaptive-spin CLH locks to reduce memory contention lessens
-     * motivation to further spread out contended locations, but might
-     * be subject to future improvements.
+     * CLH locks to reduce memory contention lessens motivation to
+     * further spread out contended locations, but might be subject to
+     * future improvements.
      */
 
     private static final long serialVersionUID = -6001602636862214147L;
 
-    /** Number of processors, for spin control */
-    private static final int NCPU = Runtime.getRuntime().availableProcessors();
-
-    /** Maximum number of retries before enqueuing on acquisition; at least 1 */
-    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1;
-
-    /** Maximum number of tries before blocking at head on acquisition */
-    private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 1;
-
-    /** Maximum number of retries before re-blocking */
-    private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 1;
-
-    /** The period for yielding when waiting for overflow spinlock */
-    private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
-
     /** The number of bits to use for reader count before overflowing */
-    private static final int LG_READERS = 7;
+    private static final int LG_READERS = 7; // 127 readers
 
     // Values for lock state and stamp operations
     private static final long RUNIT = 1L;
@@ -388,6 +319,8 @@
     private static final long RFULL = RBITS - 1L;
     private static final long ABITS = RBITS | WBIT;
     private static final long SBITS = ~RBITS; // note overlap with ABITS
+    // not writing and conservatively non-overflowing
+    private static final long RSAFE = ~(3L << (LG_READERS - 1));
 
     /*
      * 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
@@ -408,29 +341,64 @@
     // Special value from cancelled acquire methods so caller can throw IE
     private static final long INTERRUPTED = 1L;
 
-    // Values for node status; order matters
-    private static final int WAITING   = -1;
-    private static final int CANCELLED =  1;
+    // Bits for Node.status
+    static final int WAITING   = 1;
+    static final int CANCELLED = 0x80000000; // must be negative
 
-    // Modes for nodes (int not boolean to allow arithmetic)
-    private static final int RMODE = 0;
-    private static final int WMODE = 1;
+    /** CLH nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-    /** Wait nodes */
-    static final class WNode {
-        volatile WNode prev;
-        volatile WNode next;
-        volatile WNode cowait;    // list of linked readers
-        volatile Thread thread;   // non-null while possibly parked
-        volatile int status;      // 0, WAITING, or CANCELLED
-        final int mode;           // RMODE or WMODE
-        WNode(int m, WNode p) { mode = m; prev = p; }
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    static final class WriterNode extends Node { // node for writers
+    }
+
+    static final class ReaderNode extends Node { // node for readers
+        volatile ReaderNode cowaiters;           // list of linked readers
+        final boolean casCowaiters(ReaderNode c, ReaderNode v) {
+            return U.weakCompareAndSetReference(this, COWAITERS, c, v);
+        }
+        final void setCowaitersRelaxed(ReaderNode p) {
+            U.putReference(this, COWAITERS, p);
+        }
+        private static final long COWAITERS
+            = U.objectFieldOffset(ReaderNode.class, "cowaiters");
     }
 
     /** Head of CLH queue */
-    private transient volatile WNode whead;
+    private transient volatile Node head;
     /** Tail (last) of CLH queue */
-    private transient volatile WNode wtail;
+    private transient volatile Node tail;
 
     // views
     transient ReadLockView readLockView;
@@ -449,18 +417,50 @@
         state = ORIGIN;
     }
 
-    private boolean casState(long expectedValue, long newValue) {
-        return STATE.compareAndSet(this, expectedValue, newValue);
+    // internal lock methods
+
+    private boolean casState(long expect, long update) {
+        return U.compareAndSetLong(this, STATE, expect, update);
+    }
+
+    @ReservedStackAccess
+    private long tryAcquireWrite() {
+        long s, nextState;
+        if (((s = state) & ABITS) == 0L && casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return 0L;
     }
 
-    private long tryWriteLock(long s) {
-        // assert (s & ABITS) == 0L;
-        long next;
-        if (casState(s, next = s | WBIT)) {
-            VarHandle.storeStoreFence();
-            return next;
+    @ReservedStackAccess
+    private long tryAcquireRead() {
+        for (long s, m, nextState;;) {
+            if ((m = (s = state) & ABITS) < RFULL) {
+                if (casState(s, nextState = s + RUNIT))
+                    return nextState;
+            }
+            else if (m == WBIT)
+                return 0L;
+            else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                return nextState;
         }
-        return 0L;
+    }
+
+    /**
+     * Returns an unlocked state, incrementing the version and
+     * avoiding special failure value 0L.
+     *
+     * @param s a write-locked state (or stamp)
+     */
+    private static long unlockWriteState(long s) {
+        return ((s += WBIT) == 0L) ? ORIGIN : s;
+    }
+
+    private long releaseWrite(long s) {
+        long nextState = state = unlockWriteState(s);
+        signalNext(head);
+        return nextState;
     }
 
     /**
@@ -471,8 +471,13 @@
      */
     @ReservedStackAccess
     public long writeLock() {
-        long next;
-        return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
+        // try unconditional CAS confirming weak read
+        long s = U.getLongOpaque(this, STATE) & ~ABITS, nextState;
+        if (casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return acquireWrite(false, false, 0L);
     }
 
     /**
@@ -481,10 +486,8 @@
      * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryWriteLock() {
-        long s;
-        return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
+        return tryAcquireWrite();
     }
 
     /**
@@ -504,15 +507,14 @@
         throws InterruptedException {
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            long next, deadline;
-            if ((next = tryWriteLock()) != 0L)
-                return next;
+            long nextState;
+            if ((nextState = tryAcquireWrite()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireWrite(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -527,12 +529,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long writeLockInterruptibly() throws InterruptedException {
-        long next;
+        long nextState;
         if (!Thread.interrupted() &&
-            (next = acquireWrite(true, 0L)) != INTERRUPTED)
-            return next;
+            ((nextState = tryAcquireWrite()) != 0L ||
+             (nextState = acquireWrite(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -544,13 +546,12 @@
      */
     @ReservedStackAccess
     public long readLock() {
-        long s, next;
-        // bypass acquireRead on common uncontended case
-        return (whead == wtail
-                && ((s = state) & ABITS) < RFULL
-                && casState(s, next = s + RUNIT))
-            ? next
-            : acquireRead(false, 0L);
+        // unconditionally optimistically try non-overflow case once
+        long s = U.getLongOpaque(this, STATE) & RSAFE, nextState;
+        if (casState(s, nextState = s + RUNIT))
+            return nextState;
+        else
+            return acquireRead(false, false, 0L);
     }
 
     /**
@@ -559,18 +560,8 @@
      * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryReadLock() {
-        long s, m, next;
-        while ((m = (s = state) & ABITS) != WBIT) {
-            if (m < RFULL) {
-                if (casState(s, next = s + RUNIT))
-                    return next;
-            }
-            else if ((next = tryIncReaderOverflow(s)) != 0L)
-                return next;
-        }
-        return 0L;
+        return tryAcquireRead();
     }
 
     /**
@@ -586,26 +577,18 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long tryReadLock(long time, TimeUnit unit)
         throws InterruptedException {
-        long s, m, next, deadline;
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            if ((m = (s = state) & ABITS) != WBIT) {
-                if (m < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
+            long nextState;
+            if (tail == head && (nextState = tryAcquireRead()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireRead(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -620,17 +603,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long readLockInterruptibly() throws InterruptedException {
-        long s, next;
-        if (!Thread.interrupted()
-            // bypass acquireRead on common uncontended case
-            && ((whead == wtail
-                 && ((s = state) & ABITS) < RFULL
-                 && casState(s, next = s + RUNIT))
-                ||
-                (next = acquireRead(true, 0L)) != INTERRUPTED))
-            return next;
+        long nextState;
+        if (!Thread.interrupted() &&
+            ((nextState = tryAcquireRead()) != 0L ||
+             (nextState = acquireRead(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -658,29 +636,11 @@
      * since issuance of the given stamp; else false
      */
     public boolean validate(long stamp) {
-        VarHandle.acquireFence();
+        U.loadFence();
         return (stamp & SBITS) == (state & SBITS);
     }
 
     /**
-     * Returns an unlocked state, incrementing the version and
-     * avoiding special failure value 0L.
-     *
-     * @param s a write-locked state (or stamp)
-     */
-    private static long unlockWriteState(long s) {
-        return ((s += WBIT) == 0L) ? ORIGIN : s;
-    }
-
-    private long unlockWriteInternal(long s) {
-        long next; WNode h;
-        STATE.setVolatile(this, next = unlockWriteState(s));
-        if ((h = whead) != null && h.status != 0)
-            release(h);
-        return next;
-    }
-
-    /**
      * If the lock state matches the given stamp, releases the
      * exclusive lock.
      *
@@ -692,7 +652,7 @@
     public void unlockWrite(long stamp) {
         if (state != stamp || (stamp & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(stamp);
+        releaseWrite(stamp);
     }
 
     /**
@@ -705,19 +665,20 @@
      */
     @ReservedStackAccess
     public void unlockRead(long stamp) {
-        long s, m; WNode h;
-        while (((s = state) & SBITS) == (stamp & SBITS)
-               && (stamp & RBITS) > 0L
-               && ((m = s & RBITS) > 0L)) {
-            if (m < RFULL) {
-                if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+        long s, m;
+        if ((stamp & RBITS) != 0L) {
+            while (((s = state) & SBITS) == (stamp & SBITS) &&
+                   ((m = s & RBITS) != 0L)) {
+                if (m < RFULL) {
+                    if (casState(s, s - RUNIT)) {
+                        if (m == RUNIT)
+                            signalNext(head);
+                        return;
+                    }
+                }
+                else if (tryDecReaderOverflow(s) != 0L)
                     return;
-                }
             }
-            else if (tryDecReaderOverflow(s) != 0L)
-                return;
         }
         throw new IllegalMonitorStateException();
     }
@@ -730,7 +691,6 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    @ReservedStackAccess
     public void unlock(long stamp) {
         if ((stamp & WBIT) != 0L)
             unlockWrite(stamp);
@@ -751,26 +711,23 @@
      * @return a valid write stamp, or zero on failure
      */
     public long tryConvertToWriteLock(long stamp) {
-        long a = stamp & ABITS, m, s, next;
+        long a = stamp & ABITS, m, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((m = s & ABITS) == 0L) {
                 if (a != 0L)
                     break;
-                if ((next = tryWriteLock(s)) != 0L)
-                    return next;
-            }
-            else if (m == WBIT) {
+                if (casState(s, nextState = s | WBIT)) {
+                    U.storeStoreFence();
+                    return nextState;
+                }
+            } else if (m == WBIT) {
                 if (a != m)
                     break;
                 return stamp;
-            }
-            else if (m == RUNIT && a != 0L) {
-                if (casState(s, next = s - RUNIT + WBIT)) {
-                    VarHandle.storeStoreFence();
-                    return next;
-                }
-            }
-            else
+            } else if (m == RUNIT && a != 0L) {
+                if (casState(s, nextState = s - RUNIT + WBIT))
+                    return nextState;
+            } else
                 break;
         }
         return 0L;
@@ -788,28 +745,21 @@
      * @return a valid read stamp, or zero on failure
      */
     public long tryConvertToReadLock(long stamp) {
-        long a, s, next; WNode h;
+        long a, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp) // write stamp
                     break;
-                STATE.setVolatile(this, next = unlockWriteState(s) + RUNIT);
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return next;
-            }
-            else if (a == 0L) {
-                // optimistic read stamp
+                nextState = state = unlockWriteState(s) + RUNIT;
+                signalNext(head);
+                return nextState;
+            } else if (a == 0L) { // optimistic read stamp
                 if ((s & ABITS) < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
-            else {
-                // already a read stamp
+                    if (casState(s, nextState = s + RUNIT))
+                        return nextState;
+                } else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                    return nextState;
+            } else { // already a read stamp
                 if ((s & ABITS) == 0L)
                     break;
                 return stamp;
@@ -829,29 +779,25 @@
      * @return a valid optimistic read stamp, or zero on failure
      */
     public long tryConvertToOptimisticRead(long stamp) {
-        long a, m, s, next; WNode h;
-        VarHandle.acquireFence();
+        long a, m, s, nextState;
+        U.loadFence();
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp)   // write stamp
                     break;
-                return unlockWriteInternal(s);
-            }
-            else if (a == 0L)
-                // already an optimistic read stamp
+                return releaseWrite(s);
+            } else if (a == 0L) { // already an optimistic read stamp
                 return stamp;
-            else if ((m = s & ABITS) == 0L) // invalid read stamp
+            } else if ((m = s & ABITS) == 0L) { // invalid read stamp
                 break;
-            else if (m < RFULL) {
-                if (casState(s, next = s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
-                    return next & SBITS;
+            } else if (m < RFULL) {
+                if (casState(s, nextState = s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return nextState & SBITS;
                 }
-            }
-            else if ((next = tryDecReaderOverflow(s)) != 0L)
-                return next & SBITS;
+            } else if ((nextState = tryDecReaderOverflow(s)) != 0L)
+                return nextState & SBITS;
         }
         return 0L;
     }
@@ -867,7 +813,7 @@
     public boolean tryUnlockWrite() {
         long s;
         if (((s = state) & WBIT) != 0L) {
-            unlockWriteInternal(s);
+            releaseWrite(s);
             return true;
         }
         return false;
@@ -882,12 +828,12 @@
      */
     @ReservedStackAccess
     public boolean tryUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return true;
                 }
             }
@@ -1133,16 +1079,16 @@
         long s;
         if (((s = state) & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(s);
+        releaseWrite(s);
     }
 
     final void unstampedUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & RBITS) > 0L) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return;
                 }
             }
@@ -1155,10 +1101,10 @@
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
-        STATE.setVolatile(this, ORIGIN); // reset to unlocked state
+        state = ORIGIN; // reset to unlocked state
     }
 
-    // internals
+    // overflow handling methods
 
     /**
      * Tries to increment readerOverflow by first setting state
@@ -1170,17 +1116,12 @@
      */
     private long tryIncReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                ++readerOverflow;
-                STATE.setVolatile(this, s);
-                return s;
-            }
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            ++readerOverflow;
+            return state = s;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
@@ -1192,153 +1133,132 @@
      */
     private long tryDecReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                int r; long next;
-                if ((r = readerOverflow) > 0) {
-                    readerOverflow = r - 1;
-                    next = s;
-                }
-                else
-                    next = s - RUNIT;
-                STATE.setVolatile(this, next);
-                return next;
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            int r; long nextState;
+            if ((r = readerOverflow) > 0) {
+                readerOverflow = r - 1;
+                nextState = s;
             }
+            else
+                nextState = s - RUNIT;
+            return state = nextState;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
+    // release methods
+
     /**
-     * Wakes up the successor of h (normally whead). This is normally
-     * just h.next, but may require traversal from wtail if next
-     * pointers are lagging. This may fail to wake up an acquiring
-     * thread when one or more have been cancelled, but the cancel
-     * methods themselves provide extra safeguards to ensure liveness.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
      */
-    private void release(WNode h) {
-        if (h != null) {
-            WNode q; Thread w;
-            WSTATUS.compareAndSet(h, WAITING, 0);
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (q != null && (w = q.thread) != null)
-                LockSupport.unpark(w);
+    static final void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status > 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
         }
     }
 
     /**
-     * See above for explanation.
+     * Removes and unparks all cowaiters of node, if it exists.
+     */
+    private static void signalCowaiters(ReaderNode node) {
+        if (node != null) {
+            for (ReaderNode c; (c = node.cowaiters) != null; ) {
+                if (node.casCowaiters(c, c.cowaiters))
+                    LockSupport.unpark(c.waiter);
+            }
+        }
+    }
+
+    // queue link methods
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new WriterNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * For explanation, see above and AbstractQueuedSynchronizer
+     * internal documentation.
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireWrite(boolean interruptible, long deadline) {
-        WNode node = null, p;
-        for (int spins = -1;;) { // spin while enqueuing
-            long m, s, ns;
-            if ((m = (s = state) & ABITS) == 0L) {
-                if ((ns = tryWriteLock(s)) != 0L)
-                    return ns;
+    private long acquireWrite(boolean interruptible, boolean timed, long time) {
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        WriterNode node = null;
+        Node pred = null;
+        for (long s, nextState;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
             }
-            else if (spins < 0)
-                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
-            else if (spins > 0) {
+            if ((first || pred == null) && ((s = state) & ABITS) == 0L &&
+                casState(s, nextState = s | WBIT)) {
+                U.storeStoreFence();
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+                return nextState;
+            } else if (node == null) {          // retry before enqueuing
+                node = new WriterNode();
+            } else if (pred == null) {          // try to enqueue
+                Node t = tail;
+                node.setPrevRelaxed(t);
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {   // reduce unfairness
                 --spins;
                 Thread.onSpinWait();
-            }
-            else if ((p = wtail) == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(WMODE, p);
-            else if (node.prev != p)
-                node.prev = p;
-            else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                p.next = node;
-                break;
+            } else if (node.status == 0) {      // enable signal
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
             }
         }
-
-        boolean wasInterrupted = false;
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins; k > 0; --k) { // spin at head
-                    long s, ns;
-                    if (((s = state) & ABITS) == 0L) {
-                        if ((ns = tryWriteLock(s)) != 0L) {
-                            whead = node;
-                            node.prev = null;
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return ns;
-                        }
-                    }
-                    else
-                        Thread.onSpinWait();
-                }
-            }
-            else if (h != null) { // help release stale waiters
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.weakCompareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
-                }
-                else {
-                    long time; // 0 argument to park means no timeout
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
-                        whead == h && node.prev == p) {
-                        if (time == 0L)
-                            LockSupport.park(this);
-                        else
-                            LockSupport.parkNanos(this, time);
-                    }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
-                    }
-                }
-            }
-        }
+        return cancelAcquire(node, interrupted);
     }
 
     /**
@@ -1346,182 +1266,178 @@
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireRead(boolean interruptible, long deadline) {
-        boolean wasInterrupted = false;
-        WNode node = null, p;
-        for (int spins = -1;;) {
-            WNode h;
-            if ((h = whead) == (p = wtail)) {
-                for (long m, s, ns;;) {
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
+    private long acquireRead(boolean interruptible, boolean timed, long time) {
+        boolean interrupted = false;
+        ReaderNode node = null;
+        /*
+         * Loop:
+         *   if empty, try to acquire
+         *   if tail is Reader, try to cowait; restart if leader stale or cancels
+         *   else try to create and enqueue node, and wait in 2nd loop below
+         */
+        for (;;) {
+            ReaderNode leader; long nextState;
+            Node tailPred = null, t = tail;
+            if ((t == null || (tailPred = t.prev) == null) &&
+                (nextState = tryAcquireRead()) != 0L) // try now if empty
+                return nextState;
+            else if (t == null)
+                tryInitializeHead();
+            else if (tailPred == null || !(t instanceof ReaderNode)) {
+                if (node == null)
+                    node = new ReaderNode();
+                if (tail == t) {
+                    node.setPrevRelaxed(t);
+                    if (casTail(t, node)) {
+                        t.next = node;
+                        break; // node is leader; wait in loop below
                     }
-                    else if (m >= WBIT) {
-                        if (spins > 0) {
-                            --spins;
-                            Thread.onSpinWait();
-                        }
-                        else {
-                            if (spins == 0) {
-                                WNode nh = whead, np = wtail;
-                                if ((nh == h && np == p) || (h = nh) != (p = np))
-                                    break;
-                            }
-                            spins = SPINS;
-                        }
+                    node.setPrevRelaxed(null);
+                }
+            } else if ((leader = (ReaderNode)t) == tail) { // try to cowait
+                for (boolean attached = false;;) {
+                    if (leader.status < 0 || leader.prev == null)
+                        break;
+                    else if (node == null)
+                        node = new ReaderNode();
+                    else if (node.waiter == null)
+                        node.waiter = Thread.currentThread();
+                    else if (!attached) {
+                        ReaderNode c = leader.cowaiters;
+                        node.setCowaitersRelaxed(c);
+                        attached = leader.casCowaiters(c, node);
+                        if (!attached)
+                            node.setCowaitersRelaxed(null);
+                    } else {
+                        long nanos = 0L;
+                        if (!timed)
+                            LockSupport.park(this);
+                        else if ((nanos = time - System.nanoTime()) > 0L)
+                            LockSupport.parkNanos(this, nanos);
+                        interrupted |= Thread.interrupted();
+                        if ((interrupted && interruptible) ||
+                            (timed && nanos <= 0L))
+                            return cancelCowaiter(node, leader, interrupted);
                     }
                 }
-            }
-            if (p == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(RMODE, p);
-            else if (h == p || p.mode != RMODE) {
-                if (node.prev != p)
-                    node.prev = p;
-                else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                    p.next = node;
-                    break;
-                }
-            }
-            else if (!WCOWAIT.compareAndSet(p, node.cowait = p.cowait, node))
-                node.cowait = null;
-            else {
-                for (;;) {
-                    WNode pp, c; Thread w;
-                    if ((h = whead) != null && (c = h.cowait) != null &&
-                        WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null) // help release
-                        LockSupport.unpark(w);
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, p, true);
-                        wasInterrupted = true;
-                    }
-                    if (h == (pp = p.prev) || h == p || pp == null) {
-                        long m, s, ns;
-                        do {
-                            if ((m = (s = state) & ABITS) < RFULL ?
-                                casState(s, ns = s + RUNIT) :
-                                (m < WBIT &&
-                                 (ns = tryIncReaderOverflow(s)) != 0L)) {
-                                if (wasInterrupted)
-                                    Thread.currentThread().interrupt();
-                                return ns;
-                            }
-                        } while (m < WBIT);
-                    }
-                    if (whead == h && p.prev == pp) {
-                        long time;
-                        if (pp == null || h == p || p.status > 0) {
-                            node = null; // throw away
-                            break;
-                        }
-                        if (deadline == 0L)
-                            time = 0L;
-                        else if ((time = deadline - System.nanoTime()) <= 0L) {
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return cancelWaiter(node, p, false);
-                        }
-                        Thread wt = Thread.currentThread();
-                        node.thread = wt;
-                        if ((h != pp || (state & ABITS) == WBIT) &&
-                            whead == h && p.prev == pp) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
-                        }
-                        node.thread = null;
-                    }
-                }
+                if (node != null)
+                    node.waiter = null;
+                long ns = tryAcquireRead();
+                signalCowaiters(leader);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                if (ns != 0L)
+                    return ns;
+                else
+                    node = null; // restart if stale, missed, or leader cancelled
             }
         }
 
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins;;) { // spin at head
-                    long m, s, ns;
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        WNode c; Thread w;
-                        whead = node;
-                        node.prev = null;
-                        while ((c = node.cowait) != null) {
-                            if (WCOWAIT.compareAndSet(node, c, c.cowait) &&
-                                (w = c.thread) != null)
-                                LockSupport.unpark(w);
-                        }
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
-                    }
-                    else if (m >= WBIT && --k <= 0)
-                        break;
-                    else
-                        Thread.onSpinWait();
+        // node is leader of a cowait group; almost same as acquireWrite
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean first = false;
+        Node pred = null;
+        for (long nextState;;) {
+            if (!first && (pred = node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
                 }
             }
-            else if (h != null) {
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
+            if ((first || pred == null) &&
+                (nextState = tryAcquireRead()) != 0L) {
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
                 }
-                else {
-                    long time;
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 &&
-                        (p != h || (state & ABITS) == WBIT) &&
-                        whead == h && node.prev == p) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
+                signalCowaiters(node);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                return nextState;
+            } else if (first && spins != 0) {
+                --spins;
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted);
+    }
+
+    // Cancellation support
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
                     }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p && q.status >= 0) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * If leader exists, possibly repeatedly traverses cowaiters,
+     * unsplicing the given cancelled node until not found.
+     */
+    private void unlinkCowaiter(ReaderNode node, ReaderNode leader) {
+        if (leader != null) {
+            while (leader.prev != null && leader.status >= 0) {
+                for (ReaderNode p = leader, q; ; p = q) {
+                    if ((q = p.cowaiters) == null)
+                        return;
+                    if (q == node) {
+                        p.casCowaiters(q, q.cowaiters);
+                        break;  // recheck even if succeeded
                     }
                 }
             }
@@ -1530,105 +1446,53 @@
 
     /**
      * If node non-null, forces cancel status and unsplices it from
-     * queue if possible and wakes up any cowaiters (of the node, or
-     * group, as applicable), and in any case helps release current
-     * first waiter if lock is free. (Calling with null arguments
-     * serves as a conditional form of release, which is not currently
-     * needed but may be needed under possible future cancellation
-     * policies). This is a variant of cancellation methods in
-     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
-     * internal documentation).
+     * queue, wakes up any cowaiters, and possibly wakes up successor
+     * to recheck status.
      *
-     * @param node if non-null, the waiter
-     * @param group either node or the group node is cowaiting with
+     * @param node the waiter (may be null if not yet enqueued)
      * @param interrupted if already interrupted
      * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
      */
-    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
-        if (node != null && group != null) {
-            Thread w;
+    private long cancelAcquire(Node node, boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
             node.status = CANCELLED;
-            // unsplice cancelled nodes from group
-            for (WNode p = group, q; (q = p.cowait) != null;) {
-                if (q.status == CANCELLED) {
-                    WCOWAIT.compareAndSet(p, q, q.cowait);
-                    p = group; // restart
-                }
-                else
-                    p = q;
-            }
-            if (group == node) {
-                for (WNode r = group.cowait; r != null; r = r.cowait) {
-                    if ((w = r.thread) != null)
-                        LockSupport.unpark(w); // wake up uncancelled co-waiters
-                }
-                for (WNode pred = node.prev; pred != null; ) { // unsplice
-                    WNode succ, pp;        // find valid successor
-                    while ((succ = node.next) == null ||
-                           succ.status == CANCELLED) {
-                        WNode q = null;    // find successor the slow way
-                        for (WNode t = wtail; t != null && t != node; t = t.prev)
-                            if (t.status != CANCELLED)
-                                q = t;     // don't link if succ cancelled
-                        if (succ == q ||   // ensure accurate successor
-                            WNEXT.compareAndSet(node, succ, succ = q)) {
-                            if (succ == null && node == wtail)
-                                WTAIL.compareAndSet(this, node, pred);
-                            break;
-                        }
-                    }
-                    if (pred.next == node) // unsplice pred link
-                        WNEXT.compareAndSet(pred, node, succ);
-                    if (succ != null && (w = succ.thread) != null) {
-                        // wake up succ to observe new pred
-                        succ.thread = null;
-                        LockSupport.unpark(w);
-                    }
-                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
-                        break;
-                    node.prev = pp;        // repeat if new pred wrong/cancelled
-                    WNEXT.compareAndSet(pp, pred, succ);
-                    pred = pp;
-                }
-            }
-        }
-        WNode h; // Possibly release first waiter
-        while ((h = whead) != null) {
-            long s; WNode q; // similar to release() but check eligibility
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (h == whead) {
-                if (q != null && h.status == 0 &&
-                    ((s = state) & ABITS) != WBIT && // waiter is eligible
-                    (s == 0L || q.mode == RMODE))
-                    release(h);
-                break;
-            }
+            cleanQueue();
+            if (node instanceof ReaderNode)
+                signalCowaiters((ReaderNode)node);
         }
         return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle WHEAD;
-    private static final VarHandle WTAIL;
-    private static final VarHandle WNEXT;
-    private static final VarHandle WSTATUS;
-    private static final VarHandle WCOWAIT;
+    /**
+     * If node non-null, forces cancel status and unsplices from
+     * leader's cowaiters list unless/until it is also cancelled.
+     *
+     * @param node if non-null, the waiter
+     * @param leader if non-null, the node heading cowaiters list
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelCowaiter(ReaderNode node, ReaderNode leader,
+                                boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            unlinkCowaiter(node, leader);
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(StampedLock.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(StampedLock.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(StampedLock.class, "tail");
+
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(StampedLock.class, "state", long.class);
-            WHEAD = l.findVarHandle(StampedLock.class, "whead", WNode.class);
-            WTAIL = l.findVarHandle(StampedLock.class, "wtail", WNode.class);
-            WSTATUS = l.findVarHandle(WNode.class, "status", int.class);
-            WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
-            WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
+        Class<?> ensureLoaded = LockSupport.class;
     }
 }
--- a/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -136,7 +136,7 @@
             long time = timer.getTime();
             long tpi = time / (iters * nthreads);
             System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update");
-            //                double secs = (double)(time) / 1000000000.0;
+            //                double secs = (double)time / 1000000000.0;
             //                System.out.print("\t " + secs + "s run time");
             System.out.println();
 
--- a/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Sat Sep 14 11:16:40 2019 -0700
@@ -49,31 +49,51 @@
     static class MyRuntimeException extends RuntimeException {}
 
     static void checkThrowable(Throwable t) {
-        check((t instanceof MyError) ||
+        if (!((t instanceof MyError) ||
               (t instanceof MyException) ||
-              (t instanceof MyRuntimeException));
+              (t instanceof MyRuntimeException)))
+            unexpected(t);
     }
 
     static void realMain(String[] args) throws Throwable {
-        final int nThreads = 3;
+        final ThreadLocalRandom rndMain = ThreadLocalRandom.current();
+        final int nCpus = Runtime.getRuntime().availableProcessors();
+        final int maxThreads = Math.min(4, nCpus);
+        final int nThreads = rndMain.nextInt(1, maxThreads + 1);
         final int iterations = 10_000;
         final CyclicBarrier startingGate = new CyclicBarrier(nThreads);
+        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final FlakyMutex mutex = new FlakyMutex();
-        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final Runnable task = () -> {
             try {
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
                 startingGate.await();
                 for (int i = 0; i < iterations; i++) {
                     for (;;) {
-                        try { mutex.lock(); break; }
-                        catch (Throwable t) { checkThrowable(t); }
+                        try {
+                            if (rnd.nextBoolean())
+                                mutex.lock();
+                            else
+                                mutex.lockInterruptibly();
+                            break;
+                        } catch (Throwable t) { checkThrowable(t); }
                     }
 
-                    try { check(! mutex.tryLock()); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextBoolean()) {
+                        try {
+                            check(! mutex.tryLock());
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
 
-                    try { check(! mutex.tryLock(1, TimeUnit.MICROSECONDS)); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextInt(10) == 0) {
+                        try {
+                            check(! mutex.tryLock(1, TimeUnit.MICROSECONDS));
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
+
+                    if (rnd.nextBoolean()) {
+                        check(mutex.isLocked());
+                    }
 
                     mutex.unlock();
                 }
@@ -146,7 +166,11 @@
         if (x == null ? y == null : x.equals(y)) pass();
         else fail(x + " not equal to " + y);}
     public static void main(String[] args) throws Throwable {
-        try {realMain(args);} catch (Throwable t) {unexpected(t);}
+        int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+        try {
+            for (int i = runsPerTest; i--> 0; )
+                realMain(args);
+        } catch (Throwable t) { unexpected(t); }
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
     @SuppressWarnings("unchecked")
--- a/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Sat Sep 14 11:16:40 2019 -0700
@@ -42,6 +42,8 @@
 import java.io.Reader;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -72,9 +74,9 @@
         return new File(bin, programName).getPath();
     }
 
-    static final String java = javaProgramPath("java");
-    static final String jmap = javaProgramPath("jmap");
-    static final String jps  = javaProgramPath("jps");
+    static final String javaPath = javaProgramPath("java");
+    static final String jmapPath = javaProgramPath("jmap");
+    static final String jpsPath  = javaProgramPath("jps");
 
     static String outputOf(Reader r) throws IOException {
         final StringBuilder sb = new StringBuilder();
@@ -159,7 +161,11 @@
 
     static String match(String s, String regex, int group) {
         Matcher matcher = Pattern.compile(regex).matcher(s);
-        matcher.find();
+        if (! matcher.find()) {
+            String msg = String.format(
+                "match failed: s=%s regex=%s", s, regex);
+            throw new AssertionError(msg);
+        }
         return matcher.group(group);
     }
 
@@ -171,21 +177,20 @@
 
     static int objectsInUse(final Process child,
                             final String childPid,
-                            final String className) {
-        final String regex =
-            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +\\Q"+className+"\\E(?:$| )";
-        final Callable<Integer> objectsInUse =
-            new Callable<Integer>() { public Integer call() {
-                Integer i = Integer.parseInt(
-                    match(commandOutputOf(jmap, "-histo:live", childPid),
-                          regex, 1));
-                if (i > 100)
-                    System.out.print(
-                        commandOutputOf(jmap,
-                                        "-dump:file=dump,format=b",
-                                        childPid));
-                return i;
-            }};
+                            final String classNameRegex) {
+        String regex =
+            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +"+classNameRegex+"(?:$| )";
+        Callable<Integer> objectsInUse = () -> {
+            int i = Integer.parseInt(
+                match(commandOutputOf(jmapPath, "-histo:live", childPid),
+                      regex, 1));
+            if (i > 100)
+                System.out.print(
+                    commandOutputOf(jmapPath,
+                                    "-dump:file=dump,format=b",
+                                    childPid));
+            return i;
+        };
         try { return rendezvousParent(child, objectsInUse); }
         catch (Throwable t) { unexpected(t); return -1; }
     }
@@ -196,26 +201,27 @@
             return;
 
         final String childClassName = Job.class.getName();
-        final String classToCheckForLeaks = Job.classToCheckForLeaks();
-        final String uniqueID =
-            String.valueOf(ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
+        final String classNameRegex = Job.classNameRegexToCheckForLeaks();
+        final String uniqueID = String.valueOf(
+            ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
 
-        final String[] jobCmd = {
-            java, "-Xmx8m", "-XX:+UsePerfData",
-            "-classpath", System.getProperty("test.class.path"),
-            childClassName, uniqueID
-        };
+        final ArrayList<String> jobCmd = new ArrayList<>();
+        Collections.addAll(
+            jobCmd, javaPath, "-Xmx8m", "-XX:+UsePerfData",
+            "-classpath", System.getProperty("test.class.path"));
+        Collections.addAll(jobCmd, Utils.getTestJavaOpts());
+        Collections.addAll(jobCmd, childClassName, uniqueID);
         final Process p = new ProcessBuilder(jobCmd).start();
         // Ensure subprocess jvm has started, so that jps can find it
         p.getInputStream().read();
         sendByte(p.getOutputStream());
 
         final String childPid =
-            match(commandOutputOf(jps, "-m"),
+            match(commandOutputOf(jpsPath, "-m"),
                   "(?m)^ *([0-9]+) +\\Q"+childClassName+"\\E *"+uniqueID+"$", 1);
 
-        final int n0 = objectsInUse(p, childPid, classToCheckForLeaks);
-        final int n1 = objectsInUse(p, childPid, classToCheckForLeaks);
+        final int n0 = objectsInUse(p, childPid, classNameRegex);
+        final int n1 = objectsInUse(p, childPid, classNameRegex);
         equal(p.waitFor(), 0);
         equal(p.exitValue(), 0);
         failed += p.exitValue();
@@ -226,7 +232,7 @@
         // implementation, and needing occasional adjustment.
         System.out.printf("%d -> %d%n", n0, n1);
         // Almost always n0 == n1
-        // Maximum jitter observed in practice is 10 -> 17
+        // Maximum jitter observed in practice is 7
         check(Math.abs(n1 - n0) < 10);
         check(n1 < 25);
         drainers.shutdown();
@@ -244,9 +250,9 @@
     // - in between calls to rendezvousChild, run code that may leak.
     //----------------------------------------------------------------
     public static class Job {
-        static String classToCheckForLeaks() {
+        static String classNameRegexToCheckForLeaks() {
             return
-                "java.util.concurrent.locks.AbstractQueuedSynchronizer$Node";
+                "\\Qjava.util.concurrent.locks.AbstractQueuedSynchronizer$\\E[A-Za-z]+";
         }
 
         public static void main(String[] args) throws Throwable {
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -93,7 +93,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -94,7 +94,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -95,7 +95,7 @@
                 long time = timer.getTime();
                 long tpi = time / ((long)iters * nthreads);
                 System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per lock");
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -96,7 +96,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Sat Sep 14 18:45:24 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Sat Sep 14 11:16:40 2019 -0700
@@ -91,8 +91,8 @@
             premove = Integer.parseInt(args[4]);
 
         // normalize probabilities wrt random number generator
-        removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
-        insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
+        removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
+        insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
 
         System.out.println("Using " + mapClass.getName());
 
@@ -125,7 +125,7 @@
             long time = timer.getTime();
             long tpo = time / (i * (long)nops);
             System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
-            double secs = (double)(time) / 1000000000.0;
+            double secs = (double)time / 1000000000.0;
             System.out.println("\t " + secs + "s run time");
             map.clear();
         }