AQS是經過CHL隊列來實現鎖請求阻塞列表的。能夠經過acquire(int arg)來分析,當前線程競爭鎖時的流程,而後再經過release(int arg)方法來分析,當前線程釋放一個鎖時的流程。這兩個方法都是獨佔鎖的流程。相對應的acquireShared(int arg) ,releaseShared(int arg)是共享鎖的獲取釋放流程。java
/** * 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 <tt>int</tt> 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 <tt>int</tt> * value manipulated using methods {@link #getState}, {@link * #setState} and {@link #compareAndSetState} is tracked with respect * to synchronization. * 這個類根據fifo策略,實現一個阻塞鎖同步器。他設計的基礎,是依靠一個int 型的原子變量表明同步器的狀態。 * <p>Subclasses should be defined as non-public internal helper * classes that are used to implement the synchronization properties * of their enclosing class. Class * <tt>AbstractQueuedSynchronizer</tt> does not implement any * synchronization interface. Instead it defines methods such as * {@link #acquireInterruptibly} that can be invoked as * appropriate by concrete locks and related synchronizers to * implement their public methods. * * <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 "understand" 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. * 能夠根據這個類,構造共享或者獨佔模式的鎖。 * <p>This class defines a nested {@link ConditionObject} class that * can be used as a {@link Condition} implementation by subclasses * supporting exclusive mode for which method {@link * #isHeldExclusively} reports whether synchronization is exclusively * held with respect to the current thread, method {@link #release} * invoked with the current {@link #getState} value fully releases * this object, and {@link #acquire}, given this saved state value, * eventually restores this object to its previous acquired state. No * <tt>AbstractQueuedSynchronizer</tt> method otherwise creates such a * condition, so if this constraint cannot be met, do not use it. The * behavior of {@link ConditionObject} depends of course on the * semantics of its synchronizer implementation. * 類中有個內部類ConditionObject,用於實現條件隊列。 * <p>This class provides inspection, instrumentation, and monitoring * methods for the internal queue, as well as similar methods for * condition objects. These can be exported as desired into classes * using an <tt>AbstractQueuedSynchronizer</tt> for their * synchronization mechanics. * * <p>Serialization of this class stores only the underlying atomic * integer maintaining state, so deserialized objects have empty * thread queues. Typical subclasses requiring serializability will * define a <tt>readObject</tt> method that restores this to a known * initial state upon deserialization. * 。。。。。。。省略。。 * * @since 1.5 * @author Doug Lea */ public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { private static final long serialVersionUID = 7373984972572414691L; /** * Creates a new <tt>AbstractQueuedSynchronizer</tt> instance * with initial synchronization state of zero. */ protected AbstractQueuedSynchronizer() { } /** * 等待隊列的Node類: * Wait queue node class. * 等待隊列用的是CLH隊列。CLH 隊列通常用於自旋鎖隊列。 * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and * Hagersten) lock queue. CLH locks are normally used for * spinlocks. We instead use them for blocking synchronizers, but * use the same basic tactic of holding some of the control * information about a thread in the predecessor of its node. * 這裏,咱們使用相同的控制前置節點策略,把它用在阻塞同步器上。 * A "status" field in each node keeps track of whether a thread * should block. * 每一個節點的status 字段,代表這個節點是否應該阻塞。 * A node is signalled when its predecessor * releases. * 當一個節點的前置節點釋放鎖,它會獲得通知。 * Each node of the queue otherwise serves as a * specific-notification-style monitor holding a single waiting * thread. * 每一個節點,以明確通知交互方式,保存着一個等待線程。 * The status field does NOT control whether threads are * granted locks etc though. * status字段,不表明一個線程是否已經得到鎖。 * A thread may try to acquire if it is * first in the queue. But being first does not guarantee success; * it only gives the right to contend. So the currently released * contender thread may need to rewait. * 一個狀態只代表,某個線程是否有權利參與鎖競爭了。 * <p>To enqueue into a CLH lock, you atomically splice it in as new * tail. To dequeue, you just set the head field. * 一個線程入隊,就是把線程放入隊列尾部。數據結構以下圖:CLH隊列實際上是一個個Node類組成的鏈表,Node 中的waitStatus字段值表示節點的阻塞策略 * <pre> * +------+ prev +-----+ +-----+ * head | | <---- | | <---- | | tail * +------+ +-----+ +-----+ * </pre> * * <p>Insertion into a CLH queue requires only a single atomic * operation on "tail", so there is a simple atomic point of * demarcation from unqueued to queued. * 入隊在tail節點,原子操做 * Similarly, dequeing involves only updating the "head". However, it takes a bit * more work for nodes to determine who their successors are, * in part to deal with possible cancellation due to timeouts * and interrupts. * 相似地,出隊在head節點上操做,取消,還要考慮當前節點的下一個節點線程。 * <p>The "prev" links (not used in original CLH locks), are mainly * needed to handle cancellation. If a node is cancelled, its * successor is (normally) relinked to a non-cancelled * predecessor. * 節點的prev字段(在原始的 CLH locks是沒用到的)主要用於,一個節點被取消了,它的下一個節點,從新指向,它的前一個節點。 * For explanation of similar mechanics in the case * of spin locks, see the papers by Scott and Scherer at * http://www.cs.rochester.edu/u/scott/synchronization/ * 這裏的一篇論文,解釋在自旋鎖中類似的機制。 * <p>We also use "next" links to implement blocking mechanics. * The thread id for each node is kept in its own node, so a * predecessor signals the next node to wake up by traversing * next link to determine which thread it is. * 用next字段實現阻塞機制,每一個節點保存有它本身的的線程id * 前置節點能夠經過next 字段找到它的下一個節點線程去喚醒。 * 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.) * 以隊列下一個節點的方式,能夠很方便的解決,在決定誰是下一個節點時,會產生的競爭問題。 * <p>Cancellation introduces some conservatism to the basic * algorithms. Since we must poll for cancellation of other * nodes, we can miss noticing whether a cancelled node is * ahead or behind us. This is dealt with by always unparking * successors upon cancellation, allowing them to stabilize on * a new predecessor, unless we can identify an uncancelled * predecessor who will carry this responsibility. * 取消一個節點,就是它的下一個節點掛到一個新的前置節點。 * <p>CLH queues need a dummy header node to get started. But * we don't create them on construction, because it would be wasted * effort if there is never contention. Instead, the node * is constructed and head and tail pointers are set upon first * contention. * CLH隊列須要一個崗哨節點。爲了節約性能,這個節點只有在有競爭者節點時才建立, * 此時,頭結點,尾節點都同時指向這個節點。 * <p>Threads waiting on Conditions use the same nodes, but * use an additional link. Conditions only need to link nodes * in simple (non-concurrent) linked queues because they are * only accessed when exclusively held. Upon await, a node is * inserted into a condition queue. Upon signal, the node is * transferred to the main queue. A special value of status * field is used to mark which queue a node is on. * 條件隊列,使用相同的node節點。可是使用另外的連接(nextWaiter),條件隊列是非併發的隊列,由於,只用獲取排他鎖,後才能操做它。 * 當await的時候,加入條件隊列,當signal時候,把一個節點放到主隊列(鎖隊列)。 * 一個status字段值(CONDITION = -2),能夠指定當前節點時在哪一個隊列。 * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill * Scherer and Michael Scott, along with members of JSR-166 * expert group, for helpful ideas, discussions, and critiques * on the design of this class. */ static final class Node { /** Marker to indicate a node is waiting in shared mode */ static final Node SHARED = new Node();//說明節點是共享模式 /** Marker to indicate a node is waiting in exclusive mode */ static final Node EXCLUSIVE = null;//說明節點是獨佔模式 /** waitStatus value to indicate thread has cancelled */ static final int CANCELLED = 1;//說明節點線程被取消 /** waitStatus value to indicate successor's thread needs unparking */ static final int SIGNAL = -1;//說明當前線程的下一個節點是須要被調度喚醒的節點 /** waitStatus value to indicate thread is waiting on condition */ static final int CONDITION = -2;//說明節點線程在條件隊列上等待 /** * waitStatus value to indicate the next acquireShared should * unconditionally propagate//說明,下一個共享獲取,能夠無條件傳播(被喚醒)。 */ static final int PROPAGATE = -3; /** * 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 enqueing, 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; } } /** * 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; /** * Returns the current value of synchronization state. * This operation has memory semantics of a <tt>volatile</tt> read. * @return current state value */ protected final int getState() { return state; } /** * Sets the value of synchronization state. * This operation has memory semantics of a <tt>volatile</tt> write. * @param newState the new state value */ protected final void setState(int newState) { state = newState; } /** * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. * This operation has memory semantics of a <tt>volatile</tt> read * and write. * * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual * value was not equal to the expected value. */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } // Queuing utilities /** * The number of nanoseconds for which it is faster to spin * rather than to use timed park. A rough estimate suffices * to improve responsiveness with very short timeouts. */ static final long spinForTimeoutThreshold = 1000L; /** * Inserts node into queue, initializing if necessary. See picture above. * @param node the node to insert * @return node's predecessor * 把一個節點插入到等待隊列。若是有須要,初始化。 */ 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;//設置成功把當,原來的尾節點的next指向當前節點。 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;//設置成功把當,原來的尾節點的next指向當前節點。 return node;//返回最新節點。 } } enq(node);//若是當前登臺隊列爲空,把一個節點插入到等待隊列。 return node;//返回當前節點。 } /** * Sets head of queue to be node, thus dequeuing. Called only by * acquire methods. Also nulls out unused fields for sake of GC * and to suppress unnecessary signals and traversals. * * @param node the node */ private void setHead(Node node) { head = node; node.thread = null; node.prev = null; } /** * Wakes up node's successor, if one exists. * 喚醒當前節點的繼任者節點線程。 * @param node the node */ private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; if (ws < 0) 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. * 若是,繼任者已被取消或者爲null,就從尾部遍歷,找到最近的一個非取消節點。 */ 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);//native方法喚醒繼任者節點線程。 } // 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);//前置節點下一個節點爲null.刪除當前節點。 } else { // If successor needs signal, try to set pred's next-link // so it will get one. Otherwise wake it up to propagate. // 設置 當前節點的node.next爲下一個節點。 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 * 把node節點前置(沒取消)節點,waitStatus設置爲-1 * @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. * 給前置節點信號爲-1。 */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } /* * 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)) {//若是前置節點是頭節點,不停的嘗試,知道成功。說明沒有線程在等待。調用tryAcquire(arg)嘗試改變狀態變量值。 setHead(node);//若是成功了,就把當前節點設置爲頭節點,而後出列。 p.next = null; // help GC failed = false; return interrupted; } //不是頭節點,表示前面還有等待的節點。調用shouldParkAfterFailedAcquire(p, node)設置當前節點前置節點waitStatus=-1, //若是前置節點waitStatus值已被設置爲-1(返回true),接着調用parkAndCheckInterrupt()阻塞當前節點,安全放心的阻塞。 //若是前置節點waitStatus不爲-1(>0),設置前置節點的waitStatus爲-1 返回false,不阻塞當前節點。 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed)//這個正常執行不到,異常時,取消進程。 cancelAcquire(node); } } /** * 先從獲取一個排他鎖,提及, * 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)) //tryAcquire(arg)嘗試修改state狀態值,失敗返回flase, //執行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法。把當前請求線程放入隊列 selfInterrupt();//既不能修改state值,也不能入隊列的,就自我中斷。 } /** * 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)) {//若是子類實現的tryRelase返回爲true Node h = head;//把頭節點賦給h if (h != null && h.waitStatus != 0)//頭節點不爲null,而且waitStatus不爲0,爲0時下一個節點已經被喚醒 unparkSuccessor(h);//喚醒h的下個節點(即當前隊列頭第一個等待節點)若是waitStatus爲負數,就把waitStatus設置爲0 return true; } return false; } }