jdk1.8源碼分析之AbstractQueuedLongSynchronizer

AbstractQueuedLongSynchronizer 即AQS。 通過一個FIFO的雙向隊列實現的一個同步器。

  • 通過源碼瞭解AQS提供的方法,可以進一步加深對鎖實現的理解。AQS是可重入鎖,可重入讀寫鎖的一個基礎支撐,提供了一系列的方法。
  • //
    * <pre>
    *      +------+  prev +-----+       +-----+
    * head |      | <---- |     | <---- |     |  tail
    *      +------+       +-----+       +-----+
    * </pre>
    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() { }
        // 隊列 頭結點  volatile  修飾保證了可見性  transient  保證了序列化時不序列化該字段
        private transient volatile Node head;
        // 對列 尾結點
        private transient volatile Node tail;
        //  同步狀態 
        private volatile int state;
        // 爲cas 操作提供支持   unsafe 負責CAS 操作
        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 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
            * waitStatus值,指示後續線程需要釋放
             */
            static final int SIGNAL    = -1;
            
            /** waitStatus value to indicate thread is waiting on condition
            * 指示線程正在等待條件
              */
            static final int CONDITION = -2;
            /**
             * waitStatus value to indicate the next acquireShared should
             * unconditionally propagate
             * 指示下一個acquireShared應該*無條件傳播  
             */
            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;
            }
        }
        
        // AQS類 方法
        
        // 通過使用unsafed CAS 來設置state的值
        protected final boolean compareAndSetState(int expect, int update) {
            // See below for intrinsics setup to support this
            return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
        }
        
        // 插入節點,如果節點沒有初始化,則先初始化頭結點。
        // 初始化完成 ,則將使用尾插法插入node節點,返回node節點的頭結點。
        // 如果第一次調用,則返回的就是頭結點。
        private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) { // Must initialize
                 // CAS 設置頭結點
                    if (compareAndSetHead(new Node()))
                        tail = head;
                } else {
                    // node 上一個節點設置爲當前的尾結點
                    node.prev = t;
                    // CAS設置node爲尾結點
                    if (compareAndSetTail(t, node)) {
                        // node設置爲尾結點成功,則設置之前尾結點的下一個節點時node節點。
                        //這樣就構成了一個雙向的鏈表
                        t.next = node;
                        return t;
                    }
                }
            }
        }
        
        // 添加等待節點
        // mode  鎖模式,獨佔和共享
        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;
            //尾結點不爲空,則尾插法插入node節點。
            //尾結點不爲空,說明該隊列已經初始化完成
            if (pred != null) {
                node.prev = pred;
                if (compareAndSetTail(pred, node)) {
                    pred.next = node;
                    return node;
                }
            }
            // 尾結點爲空,則初始化對列,尾插法插入node節點
            enq(node);
            //返回 持有當前線程的節點,也是雙向隊列的尾結點
            return node;
        }
        
        //設置頭結點  node節點設置爲頭結點 ,頭結點持有的線程置爲null
        // 前向指針指向null
        private void setHead(Node node) {
            head = node;
            node.thread = null;
            node.prev = null;
        }
        
        // 嘗試喚醒繼任節點
        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;
            // node 節點的等待狀態小於0,則設置其等待狀態爲0
            // 0 代表是等待狀態之外的其他狀態
            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;
                //從後向前循環查找等待狀態小於等於0的節點賦值給s,至到node節點終止
                // 從後往前找到node節點第一個未被取消的繼任者 
                // 爲何這裏不從node節點開始,從前往後查找???? 因爲新節點採用尾插法插入,所以從後向前找,避免產生不可預料行爲
                for (Node t = tail; t != null && t != node; t = t.prev)
                    if (t.waitStatus <= 0)
                        s = t;
            //找到則喚醒節點的線程
            if (s != null)
                LockSupport.unpark(s.thread);
        }
        
          // 共享模式鎖的釋放
          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) {
                        //設置節點等待狀態爲0 
                        if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                            continue;            // loop to recheck cases
                            // 設置成功,則喚醒後繼者
                        unparkSuccessor(h);
                    }
                    // 等待狀態爲0,設置等待狀態爲-3失敗則返回開始處繼續循環
                    else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                        continue;                // loop on failed CAS
                }
                //等於頭結點結束循環
                if (h == head)                   // loop if head changed
                    break;
            }
        }  
        
        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.
             */
             // 原來的頭結點爲空,或者其等待狀態小於0   或
             // 現在的頭結點爲空 或者等待狀態小於0 
            if (propagate > 0 || h == null || h.waitStatus < 0 ||
                (h = head) == null || h.waitStatus < 0) {
                Node s = node.next;
                //下一個節點爲空或者是共享模式的則嘗試釋放共享鎖
                if (s == null || s.isShared())
                    doReleaseShared();
            }
        }
        
        
        // 設置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的前一個節點爲pred的前一個節點
                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.
            // pred的下一個節點
            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.
            // node 節點時尾結點,設置pred上一個節點爲尾節點
            if (node == tail && compareAndSetTail(node, pred)) {
                // 設置pred的下一個節點爲null
                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下一個節點指向自己,則此時沒有節點指向node,node不可達即可被回收
                // 爲何不直接置爲null
                node.next = node; // help GC
            }
        }
        //嘗試獲取失敗後 
        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.
                 */
                 //從pred開始循環向前找到一個未被取消的節點
                do {
                    node.prev = pred = pred.prev;
                } while (pred.waitStatus > 0);
                //找到的pred 的下一個節點置爲node。
                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.
                 */
                 //等待狀態爲0或者 PROPAGATE,則CAS嘗試將狀態設置爲 SIGNAL
                 // 
                compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
            }
            return false;
        }
        
        /**
         * Convenience method to interrupt current thread.
         */
        static void selfInterrupt() {
            // 線程中斷
            Thread.currentThread().interrupt();
        }
        
        // 優雅的掛起線程的方法,返回線程是否中斷成功
        private final boolean parkAndCheckInterrupt() {
            // 掛起線程 
            LockSupport.park(this);
            return Thread.interrupted();
        }
        
       
        /**
         * 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
         */
          // 獨佔模式獲取在隊列裏的線程,用於wait 或者acquire 方法
        final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    //node 節點的前一個節點爲頭節點  嘗試獲取鎖成功
                    if (p == head && tryAcquire(arg)) {
                        // 當前節點的線程獲取鎖成功,頭節點設置爲 node
                        setHead(node);
                        //原來的頭節點next指向null
                        p.next = null; // help GC
                        failed = false;
                        // 返回false
                        return interrupted;
                    }
                    // 獲取失敗後是否應該掛起 且 嘗試掛起 返回是否中斷成功
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
        //嘗試獲取獨佔模式對象,留給子類實現
        protected boolean tryAcquire(int arg) {
            throw new UnsupportedOperationException();
        }
        
        //獲取鎖
        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                //嘗試獲取鎖失敗,中斷當前線程
                selfInterrupt();
        }
        
        //非中斷模式獲取鎖
        //
        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;
                    }
                    // 如果node節點持有的當前線程應該被掛起且已經被中斷則拋出中斷異常
                    // 中斷異常 ,那麼實現了非中斷模式獲取鎖,如果使用此方法,
                    // 那麼 獲取鎖的線程不能被中斷
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        throw new InterruptedException();
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
        
        // 帶有超時時間獲取鎖,一旦超時則返回獲取失敗
        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);
            }
        }
        
        //共享模式嘗試獲取鎖
        private void doAcquireShared(int arg) {
            // 共享模式加入等待隊列
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    //node 的前一個節點等於頭節點
                    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);
            }
        }
        
        //鎖釋放 子類實現
        protected boolean tryRelease(int arg) {
            throw new UnsupportedOperationException();
        }
        
        // 嘗試獲取共享鎖
        protected int tryAcquireShared(int arg) {
            throw new UnsupportedOperationException();
        }
        
        //嘗試獲取鎖 
        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                //獲取失敗,線程中斷
                selfInterrupt();
        }
        
        // 釋放鎖
        public final boolean release(int arg) {
            // 嘗試釋放鎖 
            if (tryRelease(arg)) {
                Node h = head;
                //頭節點不爲空,且頭節點等待狀態不等於0 喚醒下一個等待者
                if (h != null && h.waitStatus != 0)
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
        
        // 嘗試獲取共享鎖  
        public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
        
        // 釋放共享鎖
        public final boolean releaseShared(int arg) {
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
        
        // 是否還有排隊的線程
        public final boolean hasQueuedThreads() {
            return head != tail;
        }
        
        // 是否有線程獲取過同步器
        public final boolean hasContended() {
            return head != null;
        }
        
        //返回等待最久的線程  
        public final Thread getFirstQueuedThread() {
            // handle only fast path, else relay
            return (head == tail) ? null : fullGetFirstQueuedThread();
        }
        
        // 查找最靠近頭節點的節點持有的線程
        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;
            // 從後向前循環查找節點持有的線程
            // 不是從前往後查找的原因在於有可能其他線程在設置頭節點,
            // 一種情況當前線程獲取的頭節點時原來的頭節點,當獲取頭節點的下一個節點時
            // 此時有另一個線程已經將原來頭節點的next指向null,那麼將會導致此次查找失敗。
            //這也是雙向鏈表的一個好處。頭節點在設置,從尾節點查找,避免產生衝突。
            while (t != null && t != head) {
                Thread tt = t.thread;
                if (tt != null)
                    firstThread = tt;
                t = t.prev;
            }
            return firstThread;
        }
        
        //返回給定線程是否正在排隊
        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;
        }
        
        //是否有一個排他模式的線程在等待獲取鎖
        final boolean apparentlyFirstQueuedIsExclusive() {
            Node h, s;
            return (h = head) != null &&
                (s = h.next)  != null &&
                !s.isShared()         &&
                s.thread != null;
        }
        
        // 是否有其他線程等待時間比當前線程更久
        // 用來實現公平鎖
        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());
        }
        
        // 返回對列長度
        public final int getQueueLength() {
            int n = 0;
            for (Node p = tail; p != null; p = p.prev) {
                if (p.thread != null)
                    ++n;
            }
            return n;
        }
        
        //返回隊列持有的線程集合
        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;
        }
        
        
        //返回排他模式的線程集合
        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;
        }
        
        // 獲取共享模式的線程集合
        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;
        }
        
        }
    
    

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章