AbstractQueuedSynchronizer抽象類源碼分析

上面幾章節介紹了讀寫鎖和Sync抽象類,這節介紹AQS如何控制同步的

1.首先看一下類的定義

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable

官方對類的描述爲:提供了一個框架實現阻塞鎖,依賴於同步器(信號量、事件等)以及FIFO等待隊列。該類爲大多數同步器提供了一個有用的基礎。

2.變量

    /**
     * Head of the wait queue, lazily initialized.  Except for
     * initialization, it is modified only via method setHead.  Note:
     * If head exists, its waitStatus is guaranteed not to be
     * CANCELLED.
     */
    private transient volatile Node head;//等待隊列的頭

    /**
     * Tail of the wait queue, lazily initialized.  Modified only via
     * method enq to add new wait node.
     */
    private transient volatile Node tail;//等待隊列的尾

    /**
     * The synchronization state.
     */
    private volatile int state;//同步狀態,鎖個數

3.看一下Node節點的內容

static final class Node {
        /** 標記節點在共享模式中等待 */
        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;
        /**
         * 等待狀態的枚舉值,表示下一個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;
        }

        /**
         * 返回前一個節點,如果爲空,則拋空指針異常
         *
         * @return the predecessor of this node
         */
        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;
        }
    }

4.acquireShared,獲取讀鎖時用到

    public final void acquireShared(int arg) {//在共享模式中獲取鎖
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

tryAcquireShared方法見Sync的實現,如果返回<0,說明獲取鎖失敗,會調用doAcquireShared方法

    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//等待隊列中增加一個waiter
        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);//設置head節點且喚醒下一個線程或者傳播狀態
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//獲取失敗,則檢查並更新狀態
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);//取消獲取鎖
        }
    }
    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);//設置head
        /*
         * 喚醒隊列中的下一個節點
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }
    private void doReleaseShared() {
        /*
         * 
         */
        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;
        }
    }

5.tryReadLock

        final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return false;//如果其他線程擁有寫鎖,則返回false
                int r = sharedCount(c);
                if (r == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");//如果讀鎖的個數超過最大,則報異常
                if (compareAndSetState(c, c + SHARED_UNIT)) {//如果設置狀態成功
                    if (r == 0) {//如果讀鎖爲0,設置第一個獲取到讀鎖的線程
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {//同一個線程,則讀鎖的個數加1
                        firstReaderHoldCount++;
                    } else {
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            cachedHoldCounter = rh = readHolds.get();//從threadLocal中獲取鎖個數
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                    }
                    return true;
                }
            }
        }

總結一下AQS實現的大致思路:

AQS內部維護了一個隊列管理鎖。

線程會首先嚐試獲取鎖,如果獲取失敗,則將當前線程以及等待狀態包裝成Node節點增加到等待隊列中。

接着不斷嘗試獲取鎖,如果失敗,則阻塞自己,直到被喚醒。

當持有鎖的線程釋放鎖時,會喚醒隊列中的後續線程。


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