• 彻底搞懂AQS-重点方法精讲


    彻底搞懂AQS-重点方法精讲

    ReentrantLock.java

    Snipaste_2021-10-08_11-14-37

    public class ReentrantLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = 7373984872572414699L;
        
        private final Sync sync;// 持有内部类
        
        abstract static class Sync extends AbstractQueuedSynchronizer {
           // 省略。。。。。。。。。。。。。。
        }
    
        static final class NonfairSync extends Sync {
          // 省略。。。。。。。。。。。。。。
        }
    
    
        static final class FairSync extends Sync {
           // 省略。。。。
        }
    
      
        // 无参构造函数默认生成非公平锁
        public ReentrantLock() {
            
            sync = new NonfairSync();
        }
    
       // false 代码非公平锁、 true代码公平锁
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }
    
       // reentrantLock.lock 方法
        public void lock() {
            sync.lock();
        }
    
        
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
    
       
        public boolean tryLock() {
            return sync.nonfairTryAcquire(1);
        }
    
        
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        }
    
        
        public void unlock() {
            sync.release(1);
        }
    
       
        public Condition newCondition() {
            return sync.newCondition();
        }
    
       
        public int getHoldCount() {
            return sync.getHoldCount();
        }
    
       
        public boolean isHeldByCurrentThread() {
            return sync.isHeldExclusively();
        }
    
       
        public boolean isLocked() {
            return sync.isLocked();
        }
    
       
        public final boolean isFair() {
            return sync instanceof FairSync;
        }
    
       
        protected Thread getOwner() {
            return sync.getOwner();
        }
    
        
        public final boolean hasQueuedThreads() {
            return sync.hasQueuedThreads();
        }
    
       
        public final boolean hasQueuedThread(Thread thread) {
            return sync.isQueued(thread);
        }
    
        
        public final int getQueueLength() {
            return sync.getQueueLength();
        }
    
       
        protected Collection<Thread> getQueuedThreads() {
            return sync.getQueuedThreads();
        }
    
        /**
         * Queries whether any threads are waiting on the given condition
         * associated with this lock. Note that because timeouts and
         * interrupts may occur at any time, a {@code true} return does
         * not guarantee that a future {@code signal} will awaken any
         * threads.  This method is designed primarily for use in
         * monitoring of the system state.
         *
         * @param condition the condition
         * @return {@code true} if there are any waiting threads
         * @throws IllegalMonitorStateException if this lock is not held
         * @throws IllegalArgumentException if the given condition is
         *         not associated with this lock
         * @throws NullPointerException if the condition is null
         */
        public boolean hasWaiters(Condition condition) {
            if (condition == null)
                throw new NullPointerException();
            if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
                throw new IllegalArgumentException("not owner");
            return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
        }
    
        /**
         * Returns an estimate of the number of threads waiting on the
         * given condition associated with this lock. Note that because
         * timeouts and interrupts may occur at any time, the estimate
         * serves only as an upper bound on the actual number of waiters.
         * This method is designed for use in monitoring of the system
         * state, not for synchronization control.
         *
         * @param condition the condition
         * @return the estimated number of waiting threads
         * @throws IllegalMonitorStateException if this lock is not held
         * @throws IllegalArgumentException if the given condition is
         *         not associated with this lock
         * @throws NullPointerException if the condition is null
         */
        public int getWaitQueueLength(Condition condition) {
            if (condition == null)
                throw new NullPointerException();
            if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
                throw new IllegalArgumentException("not owner");
            return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
        }
    
       
        protected Collection<Thread> getWaitingThreads(Condition condition) {
            if (condition == null)
                throw new NullPointerException();
            if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
                throw new IllegalArgumentException("not owner");
            return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
        }
    
        /**
         * Returns a string identifying this lock, as well as its lock state.
         * The state, in brackets, includes either the String {@code "Unlocked"}
         * or the String {@code "Locked by"} followed by the
         * {@linkplain Thread#getName name} of the owning thread.
         *
         * @return a string identifying this lock, as well as its lock state
         */
        public String toString() {
            Thread o = sync.getOwner();
            return super.toString() + ((o == null) ?
                                       "[Unlocked]" :
                                       "[Locked by thread " + o.getName() + "]");
        }
    }
    
    

    抽象内部类Sync 实现 AbstractQueuedSynchronizer.java

    /**
    Base of synchronization control for this lock. 
    Subclassed into fair and nonfair versions below.
    Uses AQS state to represent the number of holds on the lock.
    **/
    abstract static class Sync extends AbstractQueuedSynchronizer {
            private static final long serialVersionUID = -5179523762034025860L;
    
            abstract void lock();
    
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    
            protected final boolean tryRelease(int releases) {
                int c = getState() - releases;
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                setState(c);
                return free;
            }
    
            protected final boolean isHeldExclusively() {
                
                return getExclusiveOwnerThread() == Thread.currentThread();
            }
    
            final ConditionObject newCondition() {
                return new ConditionObject();
            }
    
    
            final Thread getOwner() {
                return getState() == 0 ? null : getExclusiveOwnerThread();
            }
    
            final int getHoldCount() {
                return isHeldExclusively() ? getState() : 0;
            }
    
            final boolean isLocked() {
                return getState() != 0;
            }
    
    
            private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
                s.defaultReadObject();
                setState(0); // reset to unlocked state
            }
        }
    
    

    AbstractQueuedSynchronizer类继承AbstractOwnableSynchronizer ,

    AbstractOwnableSynchronizer类持有exclusiveOwnerThread属性

    AbstractQueuedSynchronizer.java
    
    package java.util.concurrent.locks;
    import java.util.concurrent.TimeUnit;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Date;
    import sun.misc.Unsafe;
    
    
    public abstract class AbstractQueuedSynchronizer
        extends AbstractOwnableSynchronizer
        implements java.io.Serializable {
    
        private static final long serialVersionUID = 7373984972572414691L;
    
        /**
         * Creates a new {@code AbstractQueuedSynchronizer} instance
         * with initial synchronization state of zero.
         */
        protected AbstractQueuedSynchronizer() { }
    
        
        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;
    
            /** 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;
        
            static final int PROPAGATE = -3;
    
    
            volatile int waitStatus;
    
    
            volatile Node prev;
    
      
            volatile Node next;
    
      
            volatile Thread thread;
    
        
            Node nextWaiter;
    
            final boolean isShared() {
                return nextWaiter == SHARED;
            }
    
        
            final Node predecessor() throws NullPointerException {
                Node p = prev;
                if (p == null)
                    throw new NullPointerException();
                else
                    return p;
            }
    
            Node() {    // Used to establish initial head or SHARED marker
            }
    
            Node(Thread thread, Node mode) {     // Used by addWaiter
                this.nextWaiter = mode;
                this.thread = thread;
            }
    
            Node(Thread thread, int waitStatus) { // Used by Condition
                this.waitStatus = waitStatus;
                this.thread = thread;
            }
        }
    
        private transient volatile Node head;
    
    
        private transient volatile Node tail;
    
        private volatile int state;
    
    
        protected final int getState() {
            return state;
        }
    
        protected final void setState(int newState) {
            state = newState;
        }
    
     
        protected final boolean compareAndSetState(int expect, int update) {
            // See below for intrinsics setup to support this
            return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
        }
    
    
        static final long spinForTimeoutThreshold = 1000L;
    
    
        private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) { // Must initialize
                    if (compareAndSetHead(new Node()))
                        tail = head;
                } else {
                    node.prev = t;
                    if (compareAndSetTail(t, node)) {
                        t.next = node;
                        return t;
                    }
                }
            }
        }
    
        /**
         * Creates and enqueues node for current thread and given mode.
         *
         * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
         * @return the new node
         */
        private Node addWaiter(Node mode) {
            Node node = new Node(Thread.currentThread(), mode);
            // Try the fast path of enq; backup to full enq on failure
            Node pred = tail;
            if (pred != null) {
                node.prev = pred;
                if (compareAndSetTail(pred, node)) {
                    pred.next = node;
                    return node;
                }
            }
            enq(node);
            return 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)
                compareAndSetWaitStatus(node, 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 t = tail; t != null && t != node; t = t.prev)
                    if (t.waitStatus <= 0)
                        s = t;
            }
            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 (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                            continue;            // loop to recheck cases
                        unparkSuccessor(h);
                    }
                    else if (ws == 0 &&
                             !compareAndSetWaitStatus(h, 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.
            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)) {
                compareAndSetNext(pred, 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 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                    pred.thread != null) {
                    Node next = node.next;
                    if (next != null && next.waitStatus <= 0)
                        compareAndSetNext(pred, 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.
                 */
                compareAndSetWaitStatus(pred, 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 failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        /**
         * Acquires in exclusive interruptible mode.
         * @param arg the acquire argument
         */
        private void doAcquireInterruptibly(int arg)
            throws InterruptedException {
            final Node node = addWaiter(Node.EXCLUSIVE);
            boolean failed = true;
            try {
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        /**
         * 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);
            boolean failed = true;
            try {
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return true;
                    }
                    nanosTimeout = deadline - System.nanoTime();
                    if (nanosTimeout <= 0L)
                        return false;
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        nanosTimeout > spinForTimeoutThreshold)
                        LockSupport.parkNanos(this, nanosTimeout);
                    if (Thread.interrupted())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        /**
         * Acquires in shared uninterruptible mode.
         * @param arg the acquire argument
         */
        private void doAcquireShared(int arg) {
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head) {
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            setHeadAndPropagate(node, r);
                            p.next = null; // help GC
                            if (interrupted)
                                selfInterrupt();
                            failed = false;
                            return;
                        }
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        /**
         * Acquires in shared interruptible mode.
         * @param arg the acquire argument
         */
        private void doAcquireSharedInterruptibly(int arg)
            throws InterruptedException {
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            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
                            failed = false;
                            return;
                        }
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        /**
         * 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);
            boolean failed = true;
            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
                            failed = false;
                            return true;
                        }
                    }
                    nanosTimeout = deadline - System.nanoTime();
                    if (nanosTimeout <= 0L)
                        return false;
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        nanosTimeout > spinForTimeoutThreshold)
                        LockSupport.parkNanos(this, nanosTimeout);
                    if (Thread.interrupted())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
        // Main exported methods
    
        /**
         * Attempts to acquire in exclusive mode. This method should query
         * if the state of the object permits it to be acquired in the
         * exclusive mode, and if so to acquire it.
         *
         * <p>This method is always invoked by the thread performing
         * acquire.  If this method reports failure, the acquire method
         * may queue the thread, if it is not already queued, until it is
         * signalled by a release from some other thread. This can be used
         * to implement method {@link Lock#tryLock()}.
         *
         * <p>The default
         * implementation throws {@link UnsupportedOperationException}.
         *
         * @param arg the acquire argument. This value is always the one
         *        passed to an acquire method, or is the value saved on entry
         *        to a condition wait.  The value is otherwise uninterpreted
         *        and can represent anything you like.
         * @return {@code true} if successful. Upon success, this object has
         *         been acquired.
         * @throws IllegalMonitorStateException if acquiring would place this
         *         synchronizer in an illegal state. This exception must be
         *         thrown in a consistent fashion for synchronization to work
         *         correctly.
         * @throws UnsupportedOperationException if exclusive mode is not supported
         */
        protected boolean tryAcquire(int arg) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * Attempts to set the state to reflect a release in exclusive
         * mode.
         *
         * <p>This method is always invoked by the thread performing release.
         *
         * <p>The default implementation throws
         * {@link UnsupportedOperationException}.
         *
         * @param arg the release argument. This value is always the one
         *        passed to a release method, or the current state value upon
         *        entry to a condition wait.  The value is otherwise
         *        uninterpreted and can represent anything you like.
         * @return {@code true} if this object is now in a fully released
         *         state, so that any waiting threads may attempt to acquire;
         *         and {@code false} otherwise.
         * @throws IllegalMonitorStateException if releasing would place this
         *         synchronizer in an illegal state. This exception must be
         *         thrown in a consistent fashion for synchronization to work
         *         correctly.
         * @throws UnsupportedOperationException if exclusive mode is not supported
         */
        protected boolean tryRelease(int arg) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * Attempts to acquire in shared mode. This method should query if
         * the state of the object permits it to be acquired in the shared
         * mode, and if so to acquire it.
         *
         * <p>This method is always invoked by the thread performing
         * acquire.  If this method reports failure, the acquire method
         * may queue the thread, if it is not already queued, until it is
         * signalled by a release from some other thread.
         *
         * <p>The default implementation throws {@link
         * UnsupportedOperationException}.
         *
         * @param arg the acquire argument. This value is always the one
         *        passed to an acquire method, or is the value saved on entry
         *        to a condition wait.  The value is otherwise uninterpreted
         *        and can represent anything you like.
         * @return a negative value on failure; zero if acquisition in shared
         *         mode succeeded but no subsequent shared-mode acquire can
         *         succeed; and a positive value if acquisition in shared
         *         mode succeeded and subsequent shared-mode acquires might
         *         also succeed, in which case a subsequent waiting thread
         *         must check availability. (Support for three different
         *         return values enables this method to be used in contexts
         *         where acquires only sometimes act exclusively.)  Upon
         *         success, this object has been acquired.
         * @throws IllegalMonitorStateException if acquiring would place this
         *         synchronizer in an illegal state. This exception must be
         *         thrown in a consistent fashion for synchronization to work
         *         correctly.
         * @throws UnsupportedOperationException if shared mode is not supported
         */
        protected int tryAcquireShared(int arg) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * Attempts to set the state to reflect a release in shared mode.
         *
         * <p>This method is always invoked by the thread performing release.
         *
         * <p>The default implementation throws
         * {@link UnsupportedOperationException}.
         *
         * @param arg the release argument. This value is always the one
         *        passed to a release method, or the current state value upon
         *        entry to a condition wait.  The value is otherwise
         *        uninterpreted and can represent anything you like.
         * @return {@code true} if this release of shared mode may permit a
         *         waiting acquire (shared or exclusive) to succeed; and
         *         {@code false} otherwise
         * @throws IllegalMonitorStateException if releasing would place this
         *         synchronizer in an illegal state. This exception must be
         *         thrown in a consistent fashion for synchronization to work
         *         correctly.
         * @throws UnsupportedOperationException if shared mode is not supported
         */
        protected boolean tryReleaseShared(int arg) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * Returns {@code true} if synchronization is held exclusively with
         * respect to the current (calling) thread.  This method is invoked
         * upon each call to a non-waiting {@link ConditionObject} method.
         * (Waiting methods instead invoke {@link #release}.)
         *
         * <p>The default implementation throws {@link
         * UnsupportedOperationException}. This method is invoked
         * internally only within {@link ConditionObject} methods, so need
         * not be defined if conditions are not used.
         *
         * @return {@code true} if synchronization is held exclusively;
         *         {@code false} otherwise
         * @throws UnsupportedOperationException if conditions are not supported
         */
        protected boolean isHeldExclusively() {
            throw new UnsupportedOperationException();
        }
    
        /**
         * Acquires in exclusive mode, ignoring interrupts.  Implemented
         * by invoking at least once {@link #tryAcquire},
         * returning on success.  Otherwise the thread is queued, possibly
         * repeatedly blocking and unblocking, invoking {@link
         * #tryAcquire} until success.  This method can be used
         * to implement method {@link Lock#lock}.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquire} but is otherwise uninterpreted and
         *        can represent anything you like.
         */
        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
    
        /**
         * Acquires in exclusive mode, aborting if interrupted.
         * Implemented by first checking interrupt status, then invoking
         * at least once {@link #tryAcquire}, returning on
         * success.  Otherwise the thread is queued, possibly repeatedly
         * blocking and unblocking, invoking {@link #tryAcquire}
         * until success or the thread is interrupted.  This method can be
         * used to implement method {@link Lock#lockInterruptibly}.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquire} but is otherwise uninterpreted and
         *        can represent anything you like.
         * @throws InterruptedException if the current thread is interrupted
         */
        public final void acquireInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (!tryAcquire(arg))
                doAcquireInterruptibly(arg);
        }
    
        /**
         * Attempts to acquire in exclusive mode, aborting if interrupted,
         * and failing if the given timeout elapses.  Implemented by first
         * checking interrupt status, then invoking at least once {@link
         * #tryAcquire}, returning on success.  Otherwise, the thread is
         * queued, possibly repeatedly blocking and unblocking, invoking
         * {@link #tryAcquire} until success or the thread is interrupted
         * or the timeout elapses.  This method can be used to implement
         * method {@link Lock#tryLock(long, TimeUnit)}.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquire} but is otherwise uninterpreted and
         *        can represent anything you like.
         * @param nanosTimeout the maximum number of nanoseconds to wait
         * @return {@code true} if acquired; {@code false} if timed out
         * @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);
        }
    
        /**
         * Releases in exclusive mode.  Implemented by unblocking one or
         * more threads if {@link #tryRelease} returns true.
         * This method can be used to implement method {@link Lock#unlock}.
         *
         * @param arg the release argument.  This value is conveyed to
         *        {@link #tryRelease} but is otherwise uninterpreted and
         *        can represent anything you like.
         * @return the value returned from {@link #tryRelease}
         */
        public final boolean release(int arg) {
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    
        /**
         * Acquires in shared mode, ignoring interrupts.  Implemented by
         * first invoking at least once {@link #tryAcquireShared},
         * returning on success.  Otherwise the thread is queued, possibly
         * repeatedly blocking and unblocking, invoking {@link
         * #tryAcquireShared} until success.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquireShared} but is otherwise uninterpreted
         *        and can represent anything you like.
         */
        public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
    
        /**
         * Acquires in shared mode, aborting if interrupted.  Implemented
         * by first checking interrupt status, then invoking at least once
         * {@link #tryAcquireShared}, returning on success.  Otherwise the
         * thread is queued, possibly repeatedly blocking and unblocking,
         * invoking {@link #tryAcquireShared} until success or the thread
         * is interrupted.
         * @param arg the acquire argument.
         * This value is conveyed to {@link #tryAcquireShared} but is
         * otherwise uninterpreted and can represent anything
         * you like.
         * @throws InterruptedException if the current thread is interrupted
         */
        public final void acquireSharedInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (tryAcquireShared(arg) < 0)
                doAcquireSharedInterruptibly(arg);
        }
    
        /**
         * Attempts to acquire in shared mode, aborting if interrupted, and
         * failing if the given timeout elapses.  Implemented by first
         * checking interrupt status, then invoking at least once {@link
         * #tryAcquireShared}, returning on success.  Otherwise, the
         * thread is queued, possibly repeatedly blocking and unblocking,
         * invoking {@link #tryAcquireShared} until success or the thread
         * is interrupted or the timeout elapses.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquireShared} but is otherwise uninterpreted
         *        and can represent anything you like.
         * @param nanosTimeout the maximum number of nanoseconds to wait
         * @return {@code true} if acquired; {@code false} if timed out
         * @throws InterruptedException if the current thread is interrupted
         */
        public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            return tryAcquireShared(arg) >= 0 ||
                doAcquireSharedNanos(arg, nanosTimeout);
        }
    
        /**
         * Releases in shared mode.  Implemented by unblocking one or more
         * threads if {@link #tryReleaseShared} returns true.
         *
         * @param arg the release argument.  This value is conveyed to
         *        {@link #tryReleaseShared} but is otherwise uninterpreted
         *        and can represent anything you like.
         * @return the value returned from {@link #tryReleaseShared}
         */
        public final boolean releaseShared(int arg) {
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
    
        // Queue inspection methods
    
        /**
         * Queries whether any threads are waiting to acquire. Note that
         * because cancellations due to interrupts and timeouts may occur
         * at any time, a {@code true} return does not guarantee that any
         * other thread will ever acquire.
         *
         * <p>In this implementation, this operation returns in
         * constant time.
         *
         * @return {@code true} if there may be other threads waiting to acquire
         */
        public final boolean hasQueuedThreads() {
            return head != tail;
        }
    
        /**
         * Queries whether any threads have ever contended to acquire this
         * synchronizer; that is if an acquire method has ever blocked.
         *
         * <p>In this implementation, this operation returns in
         * constant time.
         *
         * @return {@code true} if there has ever been contention
         */
        public final boolean hasContended() {
            return head != null;
        }
    
        /**
         * Returns the first (longest-waiting) thread in the queue, or
         * {@code null} if no threads are currently queued.
         *
         * <p>In this implementation, this operation normally returns in
         * constant time, but may iterate upon contention if other threads are
         * concurrently modifying the queue.
         *
         * @return the first (longest-waiting) thread in the queue, or
         *         {@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.
             */
    
            Node t = tail;
            Thread firstThread = null;
            while (t != null && t != head) {
                Thread tt = t.thread;
                if (tt != null)
                    firstThread = tt;
                t = t.prev;
            }
            return firstThread;
        }
    
        /**
         * Returns true if the given thread is currently queued.
         *
         * <p>This implementation traverses the queue to determine
         * presence of the given thread.
         *
         * @param thread the thread
         * @return {@code true} if the given thread is on the queue
         * @throws NullPointerException if the thread is null
         */
        public final boolean isQueued(Thread thread) {
            if (thread == null)
                throw new NullPointerException();
            for (Node p = tail; p != null; p = p.prev)
                if (p.thread == thread)
                    return true;
            return false;
        }
    
        /**
         * Returns {@code true} if the apparent first queued thread, if one
         * exists, is waiting in exclusive mode.  If this method returns
         * {@code true}, and the current thread is attempting to acquire in
         * shared mode (that is, this method is invoked from {@link
         * #tryAcquireShared}) then it is guaranteed that the current thread
         * is not the first queued thread.  Used only as a heuristic in
         * ReentrantReadWriteLock.
         */
        final boolean apparentlyFirstQueuedIsExclusive() {
            Node h, s;
            return (h = head) != null &&
                (s = h.next)  != null &&
                !s.isShared()         &&
                s.thread != null;
        }
    
        /**
         * Queries whether any threads have been waiting to acquire longer
         * than the current thread.
         *
         * <p>An invocation of this method is equivalent to (but may be
         * more efficient than):
         *  <pre> {@code
         * getFirstQueuedThread() != Thread.currentThread() &&
         * hasQueuedThreads()}</pre>
         *
         * <p>Note that because cancellations due to interrupts and
         * timeouts may occur at any time, a {@code true} return does not
         * guarantee that some other thread will acquire before the current
         * thread.  Likewise, it is possible for another thread to win a
         * race to enqueue after this method has returned {@code false},
         * due to the queue being empty.
         *
         * <p>This method is designed to be used by a fair synchronizer to
         * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>.
         * Such a synchronizer's {@link #tryAcquire} method should return
         * {@code false}, and its {@link #tryAcquireShared} method should
         * return a negative value, if this method returns {@code true}
         * (unless this is a reentrant acquire).  For example, the {@code
         * tryAcquire} method for a fair, reentrant, exclusive mode
         * synchronizer might look like this:
         *
         *  <pre> {@code
         * protected boolean tryAcquire(int arg) {
         *   if (isHeldExclusively()) {
         *     // A reentrant acquire; increment hold count
         *     return true;
         *   } else if (hasQueuedPredecessors()) {
         *     return false;
         *   } else {
         *     // try to acquire normally
         *   }
         * }}</pre>
         *
         * @return {@code true} if there is a queued thread preceding the
         *         current thread, and {@code false} if the current thread
         *         is at the head of the queue or the queue is empty
         * @since 1.7
         */
        public final boolean hasQueuedPredecessors() {
            // The correctness of this depends on head being initialized
            // before tail and on head.next being accurate if the current
            // thread is first in queue.
            Node t = tail; // Read fields in reverse initialization order
            Node h = head;
            Node s;
            return h != t &&
                ((s = h.next) == null || s.thread != Thread.currentThread());
        }
    
    
        // Instrumentation and monitoring methods
    
        /**
         * Returns an estimate of the number of threads waiting to
         * acquire.  The value is only an estimate because the number of
         * threads may change dynamically while this method traverses
         * internal data structures.  This method is designed for use in
         * monitoring system state, not for synchronization
         * control.
         *
         * @return the estimated number of threads waiting to acquire
         */
        public final int getQueueLength() {
            int n = 0;
            for (Node p = tail; p != null; p = p.prev) {
                if (p.thread != null)
                    ++n;
            }
            return n;
        }
    
        /**
         * Returns a collection containing threads that may be waiting to
         * acquire.  Because the actual set of threads may change
         * dynamically while constructing this result, the returned
         * collection is only a best-effort estimate.  The elements of the
         * returned collection are in no particular order.  This method is
         * designed to facilitate construction of subclasses that provide
         * more extensive monitoring facilities.
         *
         * @return the collection of threads
         */
        public final Collection<Thread> getQueuedThreads() {
            ArrayList<Thread> list = new ArrayList<Thread>();
            for (Node p = tail; p != null; p = p.prev) {
                Thread t = p.thread;
                if (t != null)
                    list.add(t);
            }
            return list;
        }
    
        /**
         * Returns a collection containing threads that may be waiting to
         * acquire in exclusive mode. This has the same properties
         * as {@link #getQueuedThreads} except that it only returns
         * those threads waiting due to an exclusive acquire.
         *
         * @return the collection of threads
         */
        public final Collection<Thread> getExclusiveQueuedThreads() {
            ArrayList<Thread> list = new ArrayList<Thread>();
            for (Node p = tail; p != null; p = p.prev) {
                if (!p.isShared()) {
                    Thread t = p.thread;
                    if (t != null)
                        list.add(t);
                }
            }
            return list;
        }
    
        /**
         * Returns a collection containing threads that may be waiting to
         * acquire in shared mode. This has the same properties
         * as {@link #getQueuedThreads} except that it only returns
         * those threads waiting due to a shared acquire.
         *
         * @return the collection of threads
         */
        public final Collection<Thread> getSharedQueuedThreads() {
            ArrayList<Thread> list = new ArrayList<Thread>();
            for (Node p = tail; p != null; p = p.prev) {
                if (p.isShared()) {
                    Thread t = p.thread;
                    if (t != null)
                        list.add(t);
                }
            }
            return list;
        }
    
        /**
         * Returns a string identifying this synchronizer, as well as its state.
         * The state, in brackets, includes the String {@code "State ="}
         * followed by the current value of {@link #getState}, and either
         * {@code "nonempty"} or {@code "empty"} depending on whether the
         * queue is empty.
         *
         * @return a string identifying this synchronizer, as well as its state
         */
        public String toString() {
            int s = getState();
            String q  = hasQueuedThreads() ? "non" : "";
            return super.toString() +
                "[State = " + s + ", " + q + "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) {
            Node t = tail;
            for (;;) {
                if (t == node)
                    return true;
                if (t == null)
                    return false;
                t = t.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 (!compareAndSetWaitStatus(node, 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 || !compareAndSetWaitStatus(p, 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 (compareAndSetWaitStatus(node, 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) {
            boolean failed = true;
            try {
                int savedState = getState();
                if (release(savedState)) {
                    failed = false;
                    return savedState;
                } else {
                    throw new IllegalMonitorStateException();
                }
            } finally {
                if (failed)
                    node.waitStatus = Node.CANCELLED;
            }
        }
    
        // Instrumentation methods for conditions
    
        /**
         * Queries whether the given ConditionObject
         * uses this synchronizer as its lock.
         *
         * @param condition the condition
         * @return {@code true} if owned
         * @throws NullPointerException if the condition is null
         */
        public final boolean owns(ConditionObject condition) {
            return condition.isOwnedBy(this);
        }
    
        /**
         * Queries whether any threads are waiting on the given condition
         * associated with this synchronizer. Note that because timeouts
         * and interrupts may occur at any time, a {@code true} return
         * does not guarantee that a future {@code signal} will awaken
         * any threads.  This method is designed primarily for use in
         * monitoring of the system state.
         *
         * @param condition the condition
         * @return {@code true} if there are any waiting threads
         * @throws IllegalMonitorStateException if exclusive synchronization
         *         is not held
         * @throws IllegalArgumentException if the given condition is
         *         not associated with this synchronizer
         * @throws NullPointerException if the condition is null
         */
        public final boolean hasWaiters(ConditionObject condition) {
            if (!owns(condition))
                throw new IllegalArgumentException("Not owner");
            return condition.hasWaiters();
        }
    
        /**
         * Returns an estimate of the number of threads waiting on the
         * given condition associated with this synchronizer. Note that
         * because timeouts and interrupts may occur at any time, the
         * estimate serves only as an upper bound on the actual number of
         * waiters.  This method is designed for use in monitoring of the
         * system state, not for synchronization control.
         *
         * @param condition the condition
         * @return the estimated number of waiting threads
         * @throws IllegalMonitorStateException if exclusive synchronization
         *         is not held
         * @throws IllegalArgumentException if the given condition is
         *         not associated with this synchronizer
         * @throws NullPointerException if the condition is null
         */
        public final int getWaitQueueLength(ConditionObject condition) {
            if (!owns(condition))
                throw new IllegalArgumentException("Not owner");
            return condition.getWaitQueueLength();
        }
    
        /**
         * Returns a collection containing those threads that may be
         * waiting on the given condition associated with this
         * synchronizer.  Because the actual set of threads may change
         * dynamically while constructing this result, the returned
         * collection is only a best-effort estimate. The elements of the
         * returned collection are in no particular order.
         *
         * @param condition the condition
         * @return the collection of threads
         * @throws IllegalMonitorStateException if exclusive synchronization
         *         is not held
         * @throws IllegalArgumentException if the given condition is
         *         not associated with this synchronizer
         * @throws NullPointerException if the condition is null
         */
        public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
            if (!owns(condition))
                throw new IllegalArgumentException("Not owner");
            return condition.getWaitingThreads();
        }
    
        /**
         * Condition implementation for a {@link
         * AbstractQueuedSynchronizer} serving as the basis of a {@link
         * Lock} implementation.
         *
         * <p>Method documentation for this class describes mechanics,
         * not behavioral specifications from the point of view of Lock
         * and Condition users. Exported versions of this class will in
         * general need to be accompanied by documentation describing
         * condition semantics that rely on those of the associated
         * {@code AbstractQueuedSynchronizer}.
         *
         * <p>This class is Serializable, but all fields are transient,
         * so deserialized conditions have no waiters.
         */
        public class ConditionObject implements Condition, java.io.Serializable {
            private static final long serialVersionUID = 1173984872572414699L;
            /** First node of condition queue. */
            private transient Node firstWaiter;
            /** Last node of condition queue. */
            private transient Node 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() {
                Node t = lastWaiter;
                // If lastWaiter is cancelled, clean out.
                if (t != null && t.waitStatus != Node.CONDITION) {
                    unlinkCancelledWaiters();
                    t = lastWaiter;
                }
                Node node = new Node(Thread.currentThread(), 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);
            }
    
            /**
             * Removes and transfers all nodes.
             * @param first (non-null) the first node on condition queue
             */
            private void doSignalAll(Node first) {
                lastWaiter = firstWaiter = null;
                do {
                    Node next = first.nextWaiter;
                    first.nextWaiter = null;
                    transferForSignal(first);
                    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
             * owning lock.
             *
             * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
             *         returns {@code false}
             */
            public final void signal() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                Node first = firstWaiter;
                if (first != null)
                    doSignal(first);
            }
    
            /**
             * Moves all threads from the wait queue for this condition to
             * the wait queue for the owning lock.
             *
             * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
             *         returns {@code false}
             */
            public final void signalAll() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                Node first = firstWaiter;
                if (first != null)
                    doSignalAll(first);
            }
    
            /**
             * Implements uninterruptible condition wait.
             * <ol>
             * <li> Save lock state returned by {@link #getState}.
             * <li> Invoke {@link #release} with saved state as argument,
             *      throwing IllegalMonitorStateException if it fails.
             * <li> Block until signalled.
             * <li> Reacquire by invoking specialized version of
             *      {@link #acquire} with saved state as argument.
             * </ol>
             */
            public final void awaitUninterruptibly() {
                Node node = addConditionWaiter();
                int savedState = fullyRelease(node);
                boolean interrupted = false;
                while (!isOnSyncQueue(node)) {
                    LockSupport.park(this);
                    if (Thread.interrupted())
                        interrupted = true;
                }
                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();
            }
    
            /**
             * Implements interruptible condition wait.
             * <ol>
             * <li> If current thread is interrupted, throw InterruptedException.
             * <li> Save lock state returned by {@link #getState}.
             * <li> Invoke {@link #release} with saved state as argument,
             *      throwing IllegalMonitorStateException if it fails.
             * <li> Block until signalled or interrupted.
             * <li> Reacquire by invoking specialized version of
             *      {@link #acquire} with saved state as argument.
             * <li> If interrupted while blocked in step 4, throw InterruptedException.
             * </ol>
             */
            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;
                }
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    interruptMode = REINTERRUPT;
                if (node.nextWaiter != null) // clean up if cancelled
                    unlinkCancelledWaiters();
                if (interruptMode != 0)
                    reportInterruptAfterWait(interruptMode);
            }
    
            /**
             * Implements timed condition wait.
             * <ol>
             * <li> If current thread is interrupted, throw InterruptedException.
             * <li> Save lock state returned by {@link #getState}.
             * <li> Invoke {@link #release} with saved state as argument,
             *      throwing IllegalMonitorStateException if it fails.
             * <li> Block until signalled, interrupted, or timed out.
             * <li> Reacquire by invoking specialized version of
             *      {@link #acquire} with saved state as argument.
             * <li> If interrupted while blocked in step 4, throw InterruptedException.
             * </ol>
             */
            public final long awaitNanos(long nanosTimeout)
                    throws InterruptedException {
                if (Thread.interrupted())
                    throw new InterruptedException();
                Node node = addConditionWaiter();
                int savedState = fullyRelease(node);
                final long deadline = System.nanoTime() + nanosTimeout;
                int interruptMode = 0;
                while (!isOnSyncQueue(node)) {
                    if (nanosTimeout <= 0L) {
                        transferAfterCancelledWait(node);
                        break;
                    }
                    if (nanosTimeout >= spinForTimeoutThreshold)
                        LockSupport.parkNanos(this, nanosTimeout);
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                        break;
                    nanosTimeout = deadline - System.nanoTime();
                }
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    interruptMode = REINTERRUPT;
                if (node.nextWaiter != null)
                    unlinkCancelledWaiters();
                if (interruptMode != 0)
                    reportInterruptAfterWait(interruptMode);
                return deadline - System.nanoTime();
            }
    
            /**
             * Implements absolute timed condition wait.
             * <ol>
             * <li> If current thread is interrupted, throw InterruptedException.
             * <li> Save lock state returned by {@link #getState}.
             * <li> Invoke {@link #release} with saved state as argument,
             *      throwing IllegalMonitorStateException if it fails.
             * <li> Block until signalled, interrupted, or timed out.
             * <li> Reacquire by invoking specialized version of
             *      {@link #acquire} with saved state as argument.
             * <li> If interrupted while blocked in step 4, throw InterruptedException.
             * <li> If timed out while blocked in step 4, return false, else true.
             * </ol>
             */
            public final boolean awaitUntil(Date deadline)
                    throws InterruptedException {
                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;
                }
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    interruptMode = REINTERRUPT;
                if (node.nextWaiter != null)
                    unlinkCancelledWaiters();
                if (interruptMode != 0)
                    reportInterruptAfterWait(interruptMode);
                return !timedout;
            }
    
            /**
             * Implements timed condition wait.
             * <ol>
             * <li> If current thread is interrupted, throw InterruptedException.
             * <li> Save lock state returned by {@link #getState}.
             * <li> Invoke {@link #release} with saved state as argument,
             *      throwing IllegalMonitorStateException if it fails.
             * <li> Block until signalled, interrupted, or timed out.
             * <li> Reacquire by invoking specialized version of
             *      {@link #acquire} with saved state as argument.
             * <li> If interrupted while blocked in step 4, throw InterruptedException.
             * <li> If timed out while blocked in step 4, return false, else true.
             * </ol>
             */
            public final boolean await(long time, TimeUnit unit)
                    throws InterruptedException {
                long nanosTimeout = unit.toNanos(time);
                if (Thread.interrupted())
                    throw new InterruptedException();
                Node node = addConditionWaiter();
                int savedState = fullyRelease(node);
                final long deadline = System.nanoTime() + nanosTimeout;
                boolean timedout = false;
                int interruptMode = 0;
                while (!isOnSyncQueue(node)) {
                    if (nanosTimeout <= 0L) {
                        timedout = transferAfterCancelledWait(node);
                        break;
                    }
                    if (nanosTimeout >= spinForTimeoutThreshold)
                        LockSupport.parkNanos(this, nanosTimeout);
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                        break;
                    nanosTimeout = deadline - System.nanoTime();
                }
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    interruptMode = REINTERRUPT;
                if (node.nextWaiter != null)
                    unlinkCancelledWaiters();
                if (interruptMode != 0)
                    reportInterruptAfterWait(interruptMode);
                return !timedout;
            }
    
            //  support for instrumentation
    
            /**
             * Returns true if this condition was created by the given
             * synchronization object.
             *
             * @return {@code true} if owned
             */
            final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
                return sync == AbstractQueuedSynchronizer.this;
            }
    
            /**
             * Queries whether any threads are waiting on this condition.
             * Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
             *
             * @return {@code true} if there are any waiting threads
             * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
             *         returns {@code false}
             */
            protected final boolean hasWaiters() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    if (w.waitStatus == Node.CONDITION)
                        return true;
                }
                return false;
            }
    
            /**
             * Returns an estimate of the number of threads waiting on
             * this condition.
             * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
             *
             * @return the estimated number of waiting threads
             * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
             *         returns {@code false}
             */
            protected final int getWaitQueueLength() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                int n = 0;
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    if (w.waitStatus == Node.CONDITION)
                        ++n;
                }
                return n;
            }
    
            /**
             * Returns a collection containing those threads that may be
             * waiting on this Condition.
             * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
             *
             * @return the collection of threads
             * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
             *         returns {@code false}
             */
            protected final Collection<Thread> getWaitingThreads() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                ArrayList<Thread> list = new ArrayList<Thread>();
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    if (w.waitStatus == Node.CONDITION) {
                        Thread t = w.thread;
                        if (t != null)
                            list.add(t);
                    }
                }
                return list;
            }
        }
    
        /**
         * Setup to support compareAndSet. We need to natively implement
         * this here: For the sake of permitting future enhancements, we
         * cannot explicitly subclass AtomicInteger, which would be
         * efficient and useful otherwise. So, as the lesser of evils, we
         * natively implement using hotspot intrinsics API. And while we
         * are at it, we do the same for other CASable fields (which could
         * otherwise be done with atomic field updaters).
         */
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long stateOffset;
        private static final long headOffset;
        private static final long tailOffset;
        private static final long waitStatusOffset;
        private static final long nextOffset;
    
        static {
            try {
                stateOffset = unsafe.objectFieldOffset
                    (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
                headOffset = unsafe.objectFieldOffset
                    (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
                tailOffset = unsafe.objectFieldOffset
                    (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
                waitStatusOffset = unsafe.objectFieldOffset
                    (Node.class.getDeclaredField("waitStatus"));
                nextOffset = unsafe.objectFieldOffset
                    (Node.class.getDeclaredField("next"));
    
            } catch (Exception ex) { throw new Error(ex); }
        }
    
        /**
         * CAS head field. Used only by enq.
         */
        private final boolean compareAndSetHead(Node update) {
            return unsafe.compareAndSwapObject(this, headOffset, null, update);
        }
    
        /**
         * CAS tail field. Used only by enq.
         */
        private final boolean compareAndSetTail(Node expect, Node update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
        }
    
        /**
         * CAS waitStatus field of a node.
         */
        private static final boolean compareAndSetWaitStatus(Node node,
                                                             int expect,
                                                             int update) {
            return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                            expect, update);
        }
    
        /**
         * CAS next field of a node.
         */
        private static final boolean compareAndSetNext(Node node,
                                                       Node expect,
                                                       Node update) {
            return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
        }
    }
    
    

    非公平锁:NonfairSync.java

    static final class NonfairSync extends Sync {
            private static final long serialVersionUID = 7316153563782823691L;
    
            /**
             * Performs lock.  Try immediate barge, backing up to normal
             * acquire on failure.
             */
            final void lock() {
                if (compareAndSetState(0, 1))
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
            }
    
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }
        }
    

    公平锁:FairSync.java

        static final class FairSync extends Sync {
            private static final long serialVersionUID = -3000897897090466540L;
    
            final void lock() {
                acquire(1);
            }
    
            /**
             * Fair version of tryAcquire.  Don't grant access unless
             * recursive call or no waiters or is first.
             */
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
        }
    
    

    梳理代码可知,调用链关系如下:

    ReentrantLock.lock() => sync.lock() => 公平锁lock 或 非公平锁lock

    针对公平锁加锁的过程 lock

    首先我们看看加锁的过程:

    // 在ReetrantLock中的方法
        public void lock() {
            sync.lock();
        }
        // 最终是调用了FairSync中的
        final void lock() {
                acquire(1);
            }
        // 我们看看acquire
            public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }    
    
    

    当我们调用reentrantLock方法后,就会调用java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire

    1、acquire(int arg)

    那我们重点看看这个acquire方法。

    tryAcquire(arg):尝试获取锁,竞争锁成功返回true,失败返回false.

    • tryAcquire(arg)返回false,即竞争锁失败之后就会执行acquireQueued方法
    • tryAcquire(arg)返回true,竞争锁成功返回true

    acquireQueued(addWaiter(Node.EXCLUSIVE), arg):

    • 我们先来看看这个addWaiter(Node.EXCLUSIVE)方法(@see 3、addWaiter(Node.EXCLUSIVE)),
      • addWaiter 这个方法是为当前线程和给定模式创建节点并将其排队。
    • acquireQueued(final Node node, int arg):需要将成功入队的线程进行阻塞
        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                //这里为什么要中断自己? 设置一个中断标记后,将这个标记往外传。我们自己的逻辑可以用这个标记做处理,可以优雅的中断线程
                selfInterrupt();
        }
    
      static void selfInterrupt() {
            Thread.currentThread().interrupt();
      }  
    
    

    在这里插入图片描述

    那我们看看在tryAcquire中发生了啥?如下所示:

    2、acquire方法拆分之tryAcquire(int arg)

    1. AQS内部维护属性:volatile int state(32位)
      state表示资源的可用状态

    2. state三种访问方式
      getState()、setState()、compareAndSetState()

    3. AQS定义两种资源共享方式
      Exclusive 独占,只有一个线程能执行,如ReetrantLock
      Share 共享,多个线程可以同时执行,如Semaphore/CountDownLatch

    4. AQS定义两种队列
      ● 同步等待队列
      ● 条件等待队列

    尝试锁竞争方法

    为了方便理解: 约定了如下场景 : t0尝试获取锁

    
    ========================= 公平Sync的tryAcquire方法  ===========================
     /**
             * Fair version of tryAcquire.  Don't grant access unless
             * recursive call or no waiters or is first.
             */
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();// (1)
                int c = getState(); // (2) 
                if (c == 0) { // (3)
                    if (!hasQueuedPredecessors() && //(4)
                        compareAndSetState(0, acquires)) { //(5)
                        //然后设置持有独占锁的线程为当前线程
                        setExclusiveOwnerThread(current); //(6)
                        return true;
                    }
                }
     
                else if (current == getExclusiveOwnerThread()) { //(7)
                    // 只有一个线程是独占线程,下面的操作是原子操作
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc); // 此时表明只有当前一个线程竞争锁,所以不需要CAS设置state,只需要调用浦东的set方法
                    return true;
                }
                return false;
            }
    
    
    

    代码块(1) 首先是获取的当前的线程的一个引用,方便在后面操作

    代码块(2) 从信号量中后去当前竞争的情况,这是一个定义在AQS中的成员变量。用于记录当前的所有的状态。 在不同的模式中的state有不同的取值。在独占的模式中这个值的初始化化为0

    代码块(3) 获取锁状态,state = 0 表示可以加锁 :在这里会有两种情况c=0。

    • 第一种就是刚初始化的时候还没有线程来获取锁
    • 第二种就是获取的锁的线程在执行完成之后释放锁之后c也可能为0

    代码块(4)当c=0的时候首先会判断是否有排队的线程。详情查看排队线程的逻辑。如下:

    判断是否有排队线程

    3、hasQueuedPredecessors

    // AbstractQueuedSynchronizer#hasQueuedPredecessors  
    public final boolean hasQueuedPredecessors() {
            // The correctness of this depends on head being initialized
            // before tail and on head.next being accurate if the current
            // thread is first in queue.
       
            Node t = tail; // Read fields in reverse initialization order
            Node h = head;
            Node s;
            return h != t &&
                ((s = h.next) == null || s.thread != Thread.currentThread());
        }
    

    在这里的tail和head是定义在AQS中的两个变量。用于表示表示CLH队列的头节点以及尾节点 。初始化的时候tail == null & head == null 如下图所示 。 于是,判断 条件h != t 返回false。所以整个hasQueuedPredecessors方法就返回了false。

    aqs状态管理器如下所示:

    image-20211008151141215

    代码块(5) compareAndSetState将state使用CAS的方式修改为1。那在这里为何需要使用CAS呢?我们想一想在这里当多个线程同时通过第一层判断进去的时候都会去修改这个状态。但是为了保证修改的原子性使用了CAS

    代码块(6)设置持有独占锁的线程为当前线程

    t0获取锁成功,aqs状态管理器如下所示::

    image-20211008151413271

    代码流程如下所示: 橙色框框为走过的路image-20211008151740097

    代码块7 中c != 0会有两种情况。

    • 第一种:这个线程已经持有这个锁

    • 第二种:其他线程持有了这个锁

    我们看到这边如果是当前的线程持有这个锁。就直接修改的status的状态。并没有使用CAS

    那为何在这里没有使用CAS?原因很简单就是这个只会有一个线程进去 不存在多线程并发修改的问题。那小伙伴可能又会问你的state不是一个全局共享的变量么。是因为state使用了volatile关键字。底层使用了MESI协议保证不同线程之间的可见性也是在这里实现了重入,会对c 进行+1 操作

    image-20211008152343081

    reentrantLook 锁可重入,t0 再次获取锁

    此时我们的aqs状态管理器如下所示:

    image-20211008152531164

    在上面我们看了获取锁的逻辑:可以总结为如下的流程图:

    在这里插入图片描述

    场景2: 当t0获取锁后,t1尝试获取锁失败。 即state =1 ,t1 不是当前持有锁的线程t0 此时tryAcquire返回false

    image-20211008153448091

    t1在获取锁失败之后,就像我们在上面模拟的线程就会进入阻塞队列

    进入阻塞队列的逻辑如下:

    // 排队的逻辑
    acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    
    

    4、addWaiter

    构建等待队列的节点

    private Node addWaiter(Node mode) { //(1)
        Node node = new Node(Thread.currentThread(), mode);//(2)
        Node pred = tail;
        if (pred != null) { //(3)
            node.prev = pred;//(5)
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 当pred == null的时候执行入队的逻辑。详见初始化入队逻辑
        enq(node);//(4)
        return node;
    }
    ``
    **Node详解**
    ```java
    // Node是描述的CLH的节点的一种数据结构。简单的来说就是和数据结构中的
    //双向链表是非常相似的。但是呢与双向链表不同的是,他多个两个指针head、tail
    //用于标识当前队列中等待的数据的情况
    static final class Node {
    	// 描述接待你的两种状态中的共享状态。在CountDownLatch以及CyclicBarrier会使用到
        static final Node SHARED = new Node();
       // 描述节点中的独占状态
        static final Node EXCLUSIVE = null;
        // 表示当前节点的生命周期中的取消。是由于异常等原因引起的
        static final int CANCELLED =  1;
        // 描述当前节点是可以被唤醒的
        static final int SIGNAL    = -1;
        // 条件特性
        static final int CONDITION = -2;
        // 描述传播的特性
        static final int PROPAGATE = -3;
        // 这个取值就是上述的四种加上初始化时候的0这五种状态
        volatile int waitStatus;
        // 当前节点的前驱指针
        volatile Node prev;
        // 当前节点的后继指针
        volatile Node next;
        //当前处于等待状态的线程
        volatile Thread thread;
    
        Node nextWaiter;
    }
    
    
    
    
    

    代码段1 : 在AQS中的模式一共有两种。

    • 一个是独占static final Node EXCLUSIVE = null;
    • 另外的一种是共享static final Node SHARED = new Node();

    在这里的ReetrantLock使用的独占模式

    代码段2: 使用当前请求的线程以及的mode构建一个Node节点。那Node节点是啥呢?请看Node详解

    代码段3:

    • 在初始化的时候tail以及head都是null 执行代码段4:入队操作
    • 当tail不等于null时候,执行代码块5

    代码块5 详解如下

    AbstractQueuedSynchronizer既然是同步器实现框架,关键便在于处理好多线程运行时的问题。通过Java AbstractQueuedSynchronizer源码阅读1-基于队列的同步器框架,可以了解到addWaiter()的功能是将Node入队,那么addWaiter()是如何保证多线程运行下入队操作的正确性的呢?

    addWaiter()使用了原子性方法compareAndSetTail()。为方便叙述,将addWater()的代码粘贴如下:

    private Node addWaiter(Node mode) {
           Node node = new Node(Thread.currentThread(), mode);//新建与一个当前线程关联的node
           // Try the fast path of enq; backup to full enq on failure
           Node pred = tail;
           if (pred != null) {//如果tail不为空
               node.prev = pred;//将新建的node加入到队尾
               if (compareAndSetTail(pred, node)) {//调用CAS(CompareAndSet)重新设置tail
                   pred.next = node;
                   return node;
               }
           }
           //如果入队失败了,则调用enq()
           enq(node);
           return node;
       }
    

    compareAndSetTail(pred, node)会比较pred和tail是否指向同一个节点,如果是,才将tail更新为node。为何不是直接赋值,而要多做一步比较操作呢?那是因为虽然当前线程在声明pred时,为pred赋值了tail,但tail可能会被其他线程改变,而当前线程的本地变量pred是不会感知到这个改变的。

    这里,通过模拟多线程执行来加深这个理解。

    假设队列的初始状态如下,只有一个Node(称为Node0),队列的head和tail都指向Node0。

    img

    队列的初始状态

    现在有线程A和线程B同时调用addWaiter(),要向该队列插入新的Node。假设线程A和线程B的执行流程如下图所示(省略了部分代码,并对代码采取了简写):

    img

    线程A和线程B的执行流程

    第1步:线程A新建了Node(称为NodeA),并开始入队。但是,线程A仅来的及将NodeA的prev指针赋值为tail,便被调度出处理器。此时队列的状态如下图所示,NodeA的prev指向了Node0。图中还另外标注了线程A的局部变量pred,也是指向Node0的。

    img

    第1步

    第2步:紧接着,线程B开始占用处理器,执行第2步。线程2也新建了一个Node(称为NodeB),并且线程B成功的执行完addWaiter(),将NodeB入队。此时队列的状态如下图所示,NodeB的prev也指向了Node0。此处关键要注意的是,tail此时已经指向了NodeB,但是线程A的pred依然指向Node0。

    img

    第2步

    第3步:线程B在入队完成后,线程A又开始占用处理器执行。线程A调用compareAndSetTail(pred, tail),发现pred和tail并不是指向同一个Node的,该方法会返回false,线程A尝试快速入队失败。之后,线程A会调用enq(),重新获取tail,并不停尝试入队直到成功。这里不再展开enq()方法。最终队列的状态会如下所示,线程B因为先于线程A成功调用了compareAndSetTail(),而位于A的前面。

    img

    ​ 队列最终状态

    如果使用的不是CAS方法,而是直接采用赋值的方式(即将compareAndSetTail(pred, node)换成tail=node),则在第3步时,会得到下面这个错误的结果。

    img

    错误的入队

    所以说,入队的同步关键在于原子性的compareAndSetTail()方法。它保证了每个线程能够完整的执行下面两个操作:

    1. 设置prev,将自己链接到队尾;
    2. 将tail更新为自己。

    这使得队列中的tail和prev指针总是可靠的,用户在任何时候都可以使用tail和prev去访问队列。


    提出一些问题??

    为何不将如下入队的两步关键性操作封装为原子性操作

    1. 设置prev,将自己链接到队尾;
    2. 将tail更新为自己。

    如果将这两步封装为原子性操作,那么正确的入队就可以一次性完成。

    而原本的实现中,CAS失败后,还需要再重试。

    AbstractQueuedSynchronizer本身是要实现原子性的操作,而其本身又依赖原子性的操作

    其实,CAS的原子性是依赖机器指令实现的,但是机器指令无法支持以上两步执行的原子性。AbstractQueuedSynchronizer采取的方法是,依赖原子性的CAS以及循环,来实现上述两步的原子性。

    为何addWaiter()实现时,是按照下面这个顺序

    1. 设置prev指针;
    2. compareAndSetTail();
    3. 设置next指针;

    而不是3-2-1或是1-3-2这种顺序呢?

    对于3-2-1,我认为,其实和1-2-3的本质上是一样的,只是代码实现时,选择prev指针而已。1-2-3这种方式保证了prev的可靠性,可以看到AbstractQueuedSynchronizer中一些需要遍历队列的方法,如getQueuedThreads(),都是使用的prev。

    对于1-3-2,我们可以按照上面的图"线程A和线程B的执行流程“,再推演一遍,可以发现,线程A在快速入队时,对NodeA的prev指针和next指针的设置都浪费了。而1-2-3的顺序下,仅是浪费了设置prev指针这一步。

    总而言之,addWaiter()的实现保证了prev指针的可靠性。

    那么,next指针既然不可靠,那为何还需要呢?prev指针不是已经保证了队列的可访问性了么?引用源码中对Node的注释。

    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.)

    这段话的大意是说某个节点在释放锁时,需要唤醒其后继节点。如果没有next指针,那么每次都需要从tail往前遍历,next指针则优化了这一操作。但是要注意的是,因为next指针并不可靠,所以有时候next指针会是null,此时,依然需要依赖tail指针向前回溯,以找到期望的节点。

    作者:天不沽
    链接:https://www.jianshu.com/p/c806dd7f60bc
    来源:简书

    5、enq 始化入队逻辑

    private Node enq(final Node node) {
    	// 看看又是死循环。装逼点说就是自旋
        for (;;) {
            Node t = tail;//(1)
            if (t == null) {  //(2)
                if (compareAndSetHead(new Node())) // (3)
                    tail = head;
            } else { //(4)
                node.prev = t;
                if (compareAndSetTail(t, node)) { //(5)
                    t.next = node;
                    return t;
                }
            }
        }
    }
    
    

    代码段1: CLH队列还没有初始化的时候head == null & tail == null

    代码段2: 第一次初始化

    代码段3:通过CAS的方式将头部的节点初始化为空节点。初始化为空节点的原因是为了方便在后面操作。有头节点的链表操作复杂度比没有的会低很多。在这里初始化完成之后如图图一所示:

    image-20211008160802128

    代码段4: 在第一遍循环初始化好了头节点,在一次判断t == null。不成立,执行如下逻辑
    node的前驱指向初始化的节点

    代码段5:通过CAS的方式将tail节点指向新入队的节点,在修改完成之后的节点如图二所示image-20211008161710914

    入队也存在竞争,如何保证多线程运行下入队操作的正确性的呢?

    enq()使用了原子性方法compareAndSetTail()。为方便叙述,将enq()的代码进行删减如下:

    private Node enq(final Node node) {
    	// 看看又是死循环。装逼点说就是自旋
        for (;;) {
            Node t = tail;
            if (t == null) {  
    //、、、、 省略
            } else { 
                node.prev = t;
                if (compareAndSetTail(t, node)) { //(5)
                    t.next = node;
                    return t;
                }
            }
        }
    }
    

    compareAndSetTail(t, node)会比较t和tail是否指向同一个节点,如果是,才将tail更新为node。为何不是直接赋值,而要多做一步比较操作呢?那是因为虽然当前线程在声明t时,为t赋值了tail,但tail可能会被其他线程改变,而当前线程的本地变量t是不会感知到这个改变的。

    这里,通过模拟多线程执行来加深这个理解。

    现在有线程t1和线程t2、t3 同时调用enq(),要向该队列插入新的Node。

    t1成功插入队列后,此时t2在执行 代码块如下所示

     else { 
                node.prev = t;
                if (SetTail(node)) { // 不是cas判断判断t与tail是否相同,就直接队tail进行赋值为node
                    t.next = node;
                    return t;
                }
            }
    

    存在执行上述代码块不是原子操作。。

    比如:

    image-20211008181253595

    第1步:线程t2新建了Node(称为Node t2),并开始入队。但是,线程t2将Node t2的prev指针赋值为tail后,便被调度出处理器。

    此时队列的状态如下图所示,Node t2 的prev指向了Node t1。图中还另外标注了t2的局部变量t,也是指向Node t1的。

    t2 代码块在执行到 node.prev = t 时, 进程切换到t3

    image-20211008231859677

    第2步:紧接着,线程t3开始占用处理器,执行第2步。线程t3也新建了一个Node(称为Node t3),并且t3 成功的执行完代码 块,将Node t3 入队。此时队列的状态如下图所示,Node t3 的prev也指向了Node t1。此处关键要注意的是,tail此时已经指向了Node t3,但是线程t2 的t依然指向Node t1。

     else { 
                node.prev = t;
                if (SetTail(node)) { // 不是cas判断判断t与tail是否相同,就直接队tail进行赋值为node
                    t.next = node;
                    return t;
                }
            }     
    

    image-20211008232509022

    第3步:线程t3 在入队完成后,线程t2又开始占用处理器执行。如果使用的不是CAS方法,而是直接采用赋值的方式(即将compareAndSetTail(t, node)换成tail=node),则在第3步时,会得到下面这个错误的结果。

    image-20211008232929213

    简化后:

    image-20211008233029118

    我们都知道t3 此时处于阻塞的状态,需要被唤醒。 由于错误的入队导致t3 没有进入同步阻塞队列,所以t3 永远不会被唤醒。那么同理就会有成百上千的的线程无法被唤醒,而被维护在操作系统内核中,此时由于t3的prev 引用 !=null ,Node t3 也不会被gc 垃圾回收器给回收。。。

    线程t2 调用compareAndSetTail(t, tail),发现t和tail并不是指向同一个Node的,该方法会返回false 那么此时t2 则不进行入队操作。。。

    并且在下一轮 中重新更新 t的值为tail , 然后t3 重新入队。。

    总而言之 使用cas 可以保证入队成功,即重新获取tail,并不停尝试入队直到成功。

    上述的说了这么多。简单来说就是当一个线程获取锁失败之后这个线程会被放入到阻塞队列。
    那在这个过程中的流程图如下所示:

    在这里插入图片描述

    5.acquireQueued

    // 进入阻塞队列。请先看构建等待队列的节点
    final boolean acquireQueued(final Node node, int arg) {
       boolean failed = true;
       try {
           boolean interrupted = false;
           // 又是死循环
           for (;;) {
           		// 获取当前节点的前驱节点
               final Node p = node.predecessor();
               // 如果当前节点的前驱节点就是头节点。那么会再一次去尝试获取锁。那为何会在这里
               //再一次的去获取锁呢?原因很简单线程的状态切换的会消耗资源。我们都知道在Linux中
               //分为ULT和KLT。而线程的切换是需要从用户空间切换到内核空间,操作系统会把描述线程的
               //堆栈一起转入内核空间造成资源的使用。所以能不切换就不切换。在这里请求原因是我在正
               //准备切换的时候持有锁的线程释放了锁,刚好可以去获取能获取到那么就不用去阻塞
               if (p == head && tryAcquire(arg)) {
                   // 当前的线程获取到了锁,那自然是需要把当前线程从等待队列中移除。那如何去移除
                   // 只需要把节点中的prev以及thraed设置为null。让后将head指向该节点。
                   setHead(node);
                   // 然后将
                   p.next = null; // help GC
                   failed = false;
                   return interrupted;
               }
               // 要是入队的节点不是head的下一个节点执行如下的逻辑。
               // 详见修改节点的前驱节点的状态
               // 当shouldParkAfterFailedAcquire返回true之后执行
               //parkAndCheckInterrupt。在parkAndCheckInterrupt调用LockSupport将线程阻塞
               // 返回操作之后的结构
               if (shouldParkAfterFailedAcquire(p, node) &&
                   parkAndCheckInterrupt())
                   interrupted = true;
           }
       } finally {
           if (failed)
               cancelAcquire(node);
       }
    }
    
    

    我们先看:

    
    

    img

    https://blog.csdn.net/m0_53224107/article/details/117402651
    https://blog.csdn.net/scjava/article/details/108815158
    https://blog.csdn.net/qq_43631716/article/details/117394914
    https://blog.csdn.net/xiaojie_570/article/details/84196469
    https://blog.csdn.net/qq_43631716/article/details/117381486
    https://blog.csdn.net/weixin_49352973/article/details/120169974 并发编程-04. AQS 与 Lock 源码详解

  • 相关阅读:
    LeetCode Subsets II
    LeetCode Rotate Image
    LeetCode Palidrome Number
    LeetCode Generate Parentheses
    LeetCode Maximum Subarray
    LeetCode Set Matrix Zeroes
    LeetCode Remove Nth Node From End of List
    Linux Loop设备 使用
    Linux 文件系统大小调整
    LeetCode N-Queens II
  • 原文地址:https://www.cnblogs.com/tangliMeiMei/p/15383868.html
Copyright © 2020-2023  润新知