AQS源碼解析

來源:互聯網
上載者:User

標籤:upd   rup   temp   clu   檔案中   init   ica   sub   ons   

JAVA的眾多鎖的機制,包括Semaphore/ReentrantLock/ReentrantReadWriteLock等都是通過 AQS實現的,因為寫了上述幾個鎖實現的源碼分析,經常使用到AQS的原理和代碼,因此這裡做下AQS的源碼分析。這樣之後再翻看以AQS為基礎的各種各樣的鎖實現就會好理解的多了。

我們結合著源碼檔案中的注釋來看下。

原始碼英文注釋:

/** * Provides a framework for implementing blocking locks and related * synchronizers (semaphores, events, etc) that rely on * first-in-first-out (FIFO) wait queues.  This class is designed to * be a useful basis for most kinds of synchronizers that rely on a * single atomic {@code int} value to represent state. Subclasses * must define the protected methods that change this state, and which * define what that state means in terms of this object being acquired * or released.  Given these, the other methods in this class carry * out all queuing and blocking mechanics. Subclasses can maintain * other state fields, but only the atomically updated {@code int} * value manipulated using methods {@link #getState}, {@link * #setState} and {@link #compareAndSetState} is tracked with respect * to synchronization. */

提供一個依賴FIFO等待隊列來實現阻塞鎖和關聯同步機制(訊號量、事件等)的架構。該類被作為多數類型的同步機制的一個實用的基礎,設計依賴一個atomic類型的int資料來代表一個狀態。子類必須實現其protected類型的方法來改變這個狀態,這個狀態意味著對象被請求或者釋放的一個說明。提供了這些,本類的其他方法都用來執行所有的隊列和阻塞結構。子類可以維護其他的欄位,但只有state狀態的原子更新操作通過#getState, #setState, #compareAndSetState 被追蹤來實現同步。

AQS的這段類檔案中最開始的注釋,解釋了AQS類的意義和實現手段。

通過一個先進先出的隊列和一個記憶體可見的int類型狀態,來提供一個隊列的阻塞結構,作為眾多同步機制(Semaphore/ReentrantLock等)的基礎演算法結構。

原始碼英文注釋:

<p>This class supports either or both a default <em>exclusive</em> * mode and a <em>shared</em> mode. When acquired in exclusive mode, * attempted acquires by other threads cannot succeed. Shared mode * acquires by multiple threads may (but need not) succeed. This class * does not &quot;understand&quot; these differences except in the * mechanical sense that when a shared mode acquire succeeds, the next * waiting thread (if one exists) must also determine whether it can * acquire as well. Threads waiting in the different modes share the * same FIFO queue. Usually, implementation subclasses support only * one of these modes, but both can come into play for example in a * {@link ReadWriteLock}. Subclasses that support only exclusive or * only shared modes need not define the methods supporting the unused mode.

AQS類支援兩種模式,獨享模式和分享模式,預設是獨享即排它模式。排它模式時,除了當前佔用線程外,其他的線程的嘗試請求將失敗。共用模式下,多個線程的請求將會成功。這個類不能“理解”這種不同,除了這樣一種機械的功能,那就是當一個共用模式的請求成功時,另一個等待線程(如果存在的話)必須決定它是否能夠請求。不同類型的線程等待使用的是同樣的FIFO隊列。一般來說,子類只需要實現其中的一種模式,共用or排它。但也可以一起生效比如ReadWriteLock。只支援一種模式的子類不需要定義另一種不支援的模式的方法。

瞭解了基礎的概括,我們來深入代碼查看具體實現。

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; // 表明線程再等待condition條件的狀態        /**         * waitStatus value to indicate the next acquireShared should         * unconditionally propagate         */        static final int PROPAGATE = -3; // 表明下一個acquireShared會無條件的傳遞        /**         * Status field, taking on only the values:         *   SIGNAL:     The successor of this node is (or will soon be)         *               blocked (via park), so the current node must         *               unpark its successor when it releases or         *               cancels. To avoid races, acquire methods must         *               first indicate they need a signal,         *               then retry the atomic acquire, and then,         *               on failure, block.         *   CANCELLED:  This node is cancelled due to timeout or interrupt.         *               Nodes never leave this state. In particular,         *               a thread with cancelled node never again blocks.         *   CONDITION:  This node is currently on a condition queue.         *               It will not be used as a sync queue node         *               until transferred, at which time the status         *               will be set to 0. (Use of this value here has         *               nothing to do with the other uses of the         *               field, but simplifies mechanics.)         *   PROPAGATE:  A releaseShared should be propagated to other         *               nodes. This is set (for head node only) in         *               doReleaseShared to ensure propagation         *               continues, even if other operations have         *               since intervened.         *   0:          None of the above         *         * The values are arranged numerically to simplify use.         * Non-negative values mean that a node doesn‘t need to         * signal. So, most code doesn‘t need to check for particular         * values, just for sign.         *         * The field is initialized to 0 for normal sync nodes, and         * CONDITION for condition nodes.  It is modified using CAS         * (or when possible, unconditional volatile writes).         */        volatile int waitStatus;        /**         * Link to predecessor node that current node/thread relies on         * for checking waitStatus. Assigned during enqueuing, and nulled         * out (for sake of GC) only upon dequeuing.  Also, upon         * cancellation of a predecessor, we short-circuit while         * finding a non-cancelled one, which will always exist         * because the head node is never cancelled: A node becomes         * head only as a result of successful acquire. A         * cancelled thread never succeeds in acquiring, and a thread only         * cancels itself, not any other node.         */        volatile Node prev;        /**         * Link to the successor node that the current node/thread         * unparks upon release. Assigned during enqueuing, adjusted         * when bypassing cancelled predecessors, and nulled out (for         * sake of GC) when dequeued.  The enq operation does not         * assign next field of a predecessor until after attachment,         * so seeing a null next field does not necessarily mean that         * node is at end of queue. However, if a next field appears         * to be null, we can scan prev‘s from the tail to         * double-check.  The next field of cancelled nodes is set to         * point to the node itself instead of null, to make life         * easier for isOnSyncQueue.         */        volatile Node next;        /**         * The thread that enqueued this node.  Initialized on         * construction and nulled out after use.         */        volatile Thread thread;        /**         * Link to next node waiting on condition, or the special         * value SHARED.  Because condition queues are accessed only         * when holding in exclusive mode, we just need a simple         * linked queue to hold nodes while they are waiting on         * conditions. They are then transferred to the queue to         * re-acquire. And because conditions can only be exclusive,         * we save a field by using special value to indicate shared         * mode.         */        Node nextWaiter;        /**         * Returns true if node is waiting in shared mode.         */        final boolean isShared() {            return nextWaiter == SHARED;        }        /**         * Returns previous node, or throws NullPointerException if null.         * Use when predecessor cannot be null.  The null check could         * be elided, but is present to help the VM.         *         * @return the predecessor of this node         */        final Node predecessor() 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源碼解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.