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; } }