ArrayList源碼分析--jdk1.8
LinkedList源碼分析--jdk1.8
HashMap源碼分析--jdk1.8
AQS源碼分析--jdk1.8
ReentrantLock源碼分析--jdk1.8html
1. AQS是一個基於FIFO隊列,能夠用於構建鎖或者其餘相關同步裝置的基礎框架。
2. AQS提供了雙向鏈表。
3. AQS分爲共享模式和獨佔模式。
4.AQS基於volatile內存可見性和CAS原子性操做實現線程間通訊操做。java
數據結構是集合的精華所在,數據結構每每也限制了集合的做用和側重點,瞭解各類數據結構是咱們分析源碼的必經之路。
AQS的數據結構以下:雙向鏈表
AQS實現共享資源的訪問控制基礎:
1.state字段,即同步器狀態字段。用於共享資源的訪問控制
2.CLH隊列,FIFO等待隊列,存放競爭失敗的線程。一般CLH隊列是一個自旋隊列,AQS以阻塞的方式實現
CLH隊列的使用:
node
自旋鎖
學習瞭解自旋鎖以前先回顧一下互斥鎖
互斥鎖
線程在獲取互斥鎖的時候,若是發現鎖已經被其它線程佔有,那麼線程就會驚醒休眠,而後在適當的時機(好比喚醒)在獲取鎖。
自旋鎖
那麼自旋鎖顧名思義就是「自旋」。就是當一個線程在嘗試獲取鎖失敗以後,線程不會休眠或者掛起,而是一直在循環檢測鎖是否被其它線程釋放。
區別
互斥鎖就是開始開銷要大於自旋鎖。臨界區持鎖時間的大小並不會對互斥鎖的開銷形成影響,而自旋鎖是死循環檢測,加鎖全程消耗cpu,起始開銷雖然低於互斥鎖,可是隨着持鎖時間,加鎖的開銷是線性增加。
適用的狀況
互斥鎖用於臨界區持鎖時間比較長的操做,好比下面這些狀況均可以考慮安全臨界區有IO操做
臨界區代碼複雜或者循環量大
臨界區競爭很是激烈
單核處理器
自旋鎖就主要用在臨界區持鎖時間很是短且CPU資源不緊張的狀況下。當遞歸調用時有可能形成死鎖。
線程(節點)隊列
瞭解了自旋鎖以後,在學習ReentrantLock的時候,一個線程在等待鎖的時候會被封裝成一個Node節點,而後加入一個隊列中並檢測前一個節點是不是頭節點,而且嘗試獲取鎖,若是獲取鎖成功就返回,不然就阻塞。直到上一個節點釋放鎖並喚醒它。這樣看來彷佛跟自旋沒什麼掛鉤。這是由於AQS裏面的CLH隊列是CLH隊列鎖的一種變形。先來了解一下CLH隊列鎖
CLH隊列鎖
CLH(Craig, Landin, and Hagersten locks): 是一個自旋鎖,能確保無飢餓性,提供先來先服務的公平性。
CLH鎖也是一種基於鏈表的可擴展、高性能、公平的自旋鎖,申請線程只在本地變量上自旋,它不斷輪詢前驅的狀態,若是發現前驅釋放了鎖就結束自旋。http://www.2cto.com/kf/201412/363574.html這篇文章中有比較詳細的圖解。
AQS中的CLH隊列
瞭解了自旋鎖與CLH隊列鎖以後,在學習AQS中的CLH隊列就比較簡單了。AQS中的CLH隊列主要是對CLH隊列鎖改動了兩個地方
1.節點結構上作出改變。CLH隊列鎖的節點包含一個布爾類型locked的字段。若是要獲取鎖,就將這個locked設置爲true。而後就不停的輪訓前驅節點的locked是否釋放了鎖(這個過程咱們就叫作自旋)。AQS的CLH隊列在結構上引入了頭節點,尾節點。而且擁有一個前節點與下一個節點的引用。
2.在等待獲取鎖的機制上由自旋改爲了等待阻塞。
MCS
MSC與CLH最大的不一樣並非鏈表是顯示仍是隱式,而是線程自旋的規則不一樣:CLH是在前趨結點的locked域上自旋等待,而MSC是在本身的
結點的locked域上自旋等待。正由於如此,它解決了CLH在NUMA系統架構中獲取locked域狀態內存過遠的問題。數據結構
/* * 提供了一個基於FIFO隊列,能夠用於構建鎖或者其餘相關同步裝置的基礎框架 * 雙向鏈表 */ public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { /** * 無參構造方法 */ protected AbstractQueuedSynchronizer() { } /** * <pre> * +------+ prev +-----+ +-----+ * head | | <---- | | <---- | | tail * +------+ +-----+ +-----+ * </pre> */ 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 * 結點狀態 節點watiStatus的值 * CANCELLED,值爲1,終態,該節點被取消因爲超時或中斷 * SIGNAL,值爲-1,表示當前節點的後繼節點包含的線程須要運行,也就是unpark,因此當前節點release或cancels時,必須unpark它的後繼節點 * CONDITION,值爲-2,表示當前節點在等待condition,也就是在condition隊列中 該節點處於條件隊列中,將不會被用於sync queue,直到節點狀態被設置爲0 * PROPAGATE,值爲-3,表示當前場景下後續的acquireShared可以得以執行releaseShared應該被傳播到其餘節點 * 值爲0,表示當前節點在sync隊列中,等待着獲取鎖 * */ 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 * 結點狀態 */ 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; } } /** * CLH隊列中頭結點 */ private transient volatile Node head; /** * CLH隊列中尾結點 */ private transient volatile Node tail; /** * 同步狀態 * 多線程同步獲取資源成功,則state字段會自增;如有線程釋放資源,則state字段自減。 * 信號量 記錄該線程持有鎖的次數。 該線程每次釋放所 信號量 -1。 信號量爲零 表明 鎖被真正釋放 */ private volatile int state; /** * @return current state value */ protected final int getState() { return state; } /** * @param newState the new state value */ protected final void setState(int newState) { state = newState; } /** * 使用unsafe的cas比較而且交換,保證原子性 */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer。
1. AbstractOwnableSynchronizer是一個抽象類一個同步器,它可能由線程獨佔。該類爲建立可能包含全部權概念的鎖和相關同步器提供了基礎,可是,子類和工具可使用適當維護的值來幫助控制和監視訪問並提供診斷,實現了Serializable接口,定義了獨佔模式,設置和獲取獨佔模式下的線程Thread信息。
2.AbstractOwnableSynchronizer實現了Serializable接口。
1)Serializable接口,序列化接口,代表該類能夠被序列化,什麼是序列化?簡單的說,就是可以從類變成字節流傳輸,反序列化,就是從字節流變成原來的類。
3. AbstractOwnableSynchronizer是一個抽象父類,子類有AbstractQueuedSynchronizer和AbstractQueuedLongSynchronizer,它們2個之間的區別就是異常將全部與狀態相關的參數和結果定義爲long類型而不是int類型,在建立同步器(例如多級鎖和須要64位狀態的障礙)時,此類可能頗有用。 多線程
1)acquire(int arg);
以獨佔模式獲取資源,若是獲取成功,直接返回,不然進去CLH等待隊列,經過自旋知道獲取到資源爲止,過程當中忽略線程中斷,獲取資源後才進行自我中斷(補上),下面看源碼:架構
/** * AQS的獨佔模式--互斥 * tryAcquire()嘗試直接去獲取資源,若是成功則直接返回; * addWaiter()將該線程加入等待隊列的尾部,並標記爲獨佔模式; * acquireQueued()使線程在等待隊列中獲取資源,一直獲取到資源後才返回。若是在整個等待過程當中被中斷過,則返回true,不然返回false。 * 若是線程在等待過程當中被中斷過,它是不響應的。只是獲取資源後纔再進行自我中斷selfInterrupt(),將中斷補上。 */ public final void acquire(int arg) { if (!tryAcquire(arg) && // 再次嘗試上鎖 回到了 NonfairSync.tryAcquire 方法, tryAcquire 調用了 Sync.nonfairTryAcquire方法 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 鏈表尾部添加節點 爲獨佔模式 selfInterrupt(); }
2)boolean tryAcquire(int arg);
嘗試以獨佔的方式獲取資源,成功true,失敗false,該方法能夠用於實現Lock中的tryLock()方法。框架
/** * tryAcquire嘗試以獨佔的方式獲取資源,若是獲取成功,則直接返回true,不然直接返回false。該方法能夠用於實現Lock中的tryLock()方法。 * 該方法的默認實現是拋出UnsupportedOperationException,具體實現由自定義的擴展了AQS的同步類來實現。AQS在這裏只負責定義了一個公共的方法框架。 * 這裏之因此沒有定義成abstract,是由於獨佔模式下只用實現tryAcquire-tryRelease,而共享模式下只用實現tryAcquireShared-tryReleaseShared。 * 若是都定義成abstract,那麼每一個模式也要去實現另外一模式下的接口 * 由子類選擇性實現 */ protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
3)Node addWaiter(Node mode);
將一個Node節點放入到CLH隊列的隊尾。ide
/** * 將一個Node節點放入到CLH隊列的隊尾。 * 第一步:首先將oldTail賦值給newNode.prev:node.prev = pred, 把當前tail節點賦值到mode新節點的prev前一個, * 第二步:將tail賦值給newNode:compareAndSetTail(pred, node) 把當前tail節點的內存地址修改成(指向)新的mode節點, * 第三步:將oldTail的next指針指向newNode(即tail):pred.next = node 把當前tail節點的next後一個賦值爲新的mode節點(即tail) * 若是隊列爲空,經過enq(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 //嘗試快速入隊,失敗則使用enq()方式 Node pred = tail; if (pred != null) { // 列隊尾部不爲空 node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // 列隊尾部爲空 或者 CAS 操做失敗 enq(node); return node; }
4)boolean acquireQueued(final Node node, int arg);
使線程在等待隊列中獲取資源,一直獲取到資源後才返回。若是在整個等待過程當中被中斷過,則返回true,不然返回false。函數
/** * 若node節點的前繼節點是head節點,則會再次調用tryAcquire()獲取資源 * 判斷當前節點的前繼節點是否爲head節點。如果,則表示該節點有資格嘗試獲取共享資源。此處的head節點的判斷在必定程度上保證資源競爭的公平性 * shouldParkAfterFailedAcquire():判斷當前節點是否能夠安全進入park() * parkAndCheckInterrupt():讓線程進入等待 * 用於隊列中的線程自旋地以獨佔且不可中斷的方式獲取同步狀態(acquire),直到拿到鎖以後再返回。該方法的實現分紅兩部分: * 若是當前節點已經成爲頭結點,嘗試獲取鎖(tryAcquire)成功,而後返回;不然檢查當前節點是否應該被park,而後將該線程park而且檢查當前線程是否被能夠被中斷 */ final boolean acquireQueued(final Node node, int arg) { //標記是否成功拿到資源,默認false boolean failed = true; try { boolean interrupted = false;//標記等待過程當中是否被中斷過 for (;;) { final Node p = node.predecessor(); // 判斷當前節點的 前驅節點 是否爲隊列頭部 若是是 再次嘗試上鎖(若是頭部節點 已經釋放鎖, 則使當前線程成爲持有者 而且設置本身爲 頭部。 同時釋放前驅節點) if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } //判斷當前節點是否能夠進入park,若能夠,讓線程進入等待 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { //若是獲取資源失敗,則取消 if (failed) cancelAcquire(node); } }
5)void selfInterrupt();
中斷當前線程
/** * Convenience method to interrupt current thread. * 中斷當前線程 */ static void selfInterrupt() { Thread.currentThread().interrupt(); }
6)Node enq(final Node node);
將當前節點插入等待隊列
/** * 進行自旋入隊方式的enq()方法,基本和addWaiter()方法一致: * 用於將當前節點插入等待隊列,若是隊列爲空,則初始化當前隊列。整個過程以CAS自旋的方式進行,直到成功加入隊尾爲止 */ private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize 必須初始化 尾部爲空 嘗試構建表結構 if (compareAndSetHead(new Node())) tail = head; } else { //尾部不爲空 不斷嘗試 CAS 操做 node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
7)boolean compareAndSetHead(Node update);
經過原子(CAS)操做 改變上鎖狀態
/** * CAS head field. Used only by enq. * 經過原子操做 改變上鎖狀態 * this == null * 第一個參數爲須要改變的對象,第二個爲偏移量(即以前求出來的valueOffset的值),第三個參數爲期待的值,第四個爲更新後的值 */ private final boolean compareAndSetHead(Node update) { //調用本地方法 實現硬件級別的原子操做 cas return unsafe.compareAndSwapObject(this, headOffset, null, update); }
8)boolean parkAndCheckInterrupt();
讓線程去休息,真正進入等待狀態
/** * 該方法讓線程去休息,真正進入等待狀態。park()會讓當前線程進入waiting狀態。在此狀態下,有兩種途徑能夠喚醒該線程: * 1)被unpark();2)被interrupt()。須要注意的是,Thread.interrupted()會清除當前線程的中斷標記位 */ private final boolean parkAndCheckInterrupt() { LockSupport.park(this); // 又是一個底層類 實現線程等待 return Thread.interrupted(); }
9)boolean shouldParkAfterFailedAcquire(Node pred, Node node);
判斷當前節點中的線程,是否能夠安全的進入park()。返回true,表示進程能夠進入park
/** * 該方法的做用在於判斷當前節點中的線程,是否能夠安全的進入park()。返回true,表示進程能夠進入park。若前驅節點的waitStatus爲SIGNAL,則表示當前節點能夠安全的park()。 */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; //若是前驅節點的waitStatus爲SIGNAL -1,則表示當前節點能夠安全的park() if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; // waitStatus>0,即爲CANCELLED狀態,此時當前節點須要找到狀態不爲CANCELLED狀態的節點,將其設置爲本身的前驅節點,並將新的前驅節點的next指向本身。 // 注意,這樣作完以後,那些當前節點的waitStatus狀態爲CANCELLED的前驅節點鏈,將成爲孤鏈。但這個孤鏈仍然有指向原等待隊列的prev和next指針。只是原等待隊列中已經沒有指向孤鏈的節點指針 // 將前驅節點移出列隊 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. */ // 走到此處,代表前驅節點的狀態爲0或PROPAGATE。此時能夠將前驅節點的waitStatus設置爲SIGNAL狀態 // 注意:這裏仍然要返回false,代表當前節點不能被park。咱們須要在park以前,重試確認該節點不能獲取到資源 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
1)acquireShared(int arg);
以共享模式獲取資源,若是獲取成功,直接返回,不然進去CLH等待隊列,經過自旋知道獲取到資源爲止,過程當中忽略線程中斷,獲取資源後才進行自我中斷(補上),下面看源碼:
/** * aqs的共享模式 * 獲取指定量的資源,獲取成功則直接返回,獲取失敗則進入等待隊列,直到獲取到資源爲止,整個過程忽略中斷 */ public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); }
2)int tryAcquireShared(int arg);
嘗試以共享的方式獲取資源,成功true,失敗false,該方法能夠用於實現Lock中的tryLock()方法。
/** * tryAcquireShared嘗試以共享的方式獲取資源,若是獲取成功,則直接返回true,不然直接返回false。該方法能夠用於實現Lock中的tryLock()方法。 * 該方法的默認實現是拋出UnsupportedOperationException,具體實現由自定義的擴展了AQS的同步類來實現。AQS在這裏只負責定義了一個公共的方法框架。 * 這裏之因此沒有定義成abstract,是由於獨佔模式下只用實現tryAcquire-tryRelease,而共享模式下只用實現tryAcquireShared-tryReleaseShared。 * 若是都定義成abstract,那麼每一個模式也要去實現另外一模式下的接口 */ protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); }
3)doAcquireShared(int arg);
將當前線程加入等待隊列尾部休息,直到其餘線程釋放資源喚醒本身,本身成功拿到相應量的資源後才返回
/** * Acquires in shared uninterruptible mode. * @param arg the acquire argument * 將當前線程加入等待隊列尾部休息,直到其餘線程釋放資源喚醒本身,本身成功拿到相應量的資源後才返回 */ private void doAcquireShared(int arg) { final Node node = addWaiter(Node.SHARED); 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); p.next = null; // help GC if (interrupted) selfInterrupt(); failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
4)boolean parkAndCheckInterrupt();
讓線程去休息,真正進入等待狀態
/** * 該方法讓線程去休息,真正進入等待狀態。park()會讓當前線程進入waiting狀態。在此狀態下,有兩種途徑能夠喚醒該線程: * 1)被unpark();2)被interrupt()。須要注意的是,Thread.interrupted()會清除當前線程的中斷標記位 */ private final boolean parkAndCheckInterrupt() { LockSupport.park(this); // 又是一個底層類 實現線程等待 return Thread.interrupted(); }
5)cancelAcquire(Node node);
取消節點
/** * 取消節點 * 列隊等待中 拋出異常會調用此方法 */ private void cancelAcquire(Node node) { // Ignore if node doesn't exist if (node == null) return; //找到適合的前繼節點,當前節點的waitStatus賦值爲CANCELLED node.thread = null; // 釋放線程 // Skip cancelled predecessors 前驅節點已被取消 從新定義前驅節點 Node pred = node.prev; //若前繼節點是CANCELLED,則繼續找前繼節點,直至找到一個正常的前繼節點賦值給node,做爲node的新前繼節點 while (pred.waitStatus > 0) node.prev = pred = pred.prev; Node predNext = pred.next; node.waitStatus = Node.CANCELLED; // 取消當前線程 所屬的節點(標記爲取消), 沒有使用 cas 由於 其餘線程 不會干擾這裏 // If we are the tail, remove ourselves. //特殊狀況:node==tail節點,將pred做爲tail節點,而後將cancelledNodes節點鏈從CLH隊列剔除 if (node == tail && compareAndSetTail(node, pred)) { 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; //正常狀況:則將cancelledNodes節點鏈從CLH隊列剔除 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 { //特殊狀況:若是node是head的後繼節點,則直接喚醒node的後繼節點 pred==head節點:嘗試調用unparkSuccessor(node),嘗試喚醒當前節點的後繼節點 unparkSuccessor(node); } node.next = node; // help GC } }
6)unparkSuccessor(Node node);
喚醒後繼節點
/** * 喚醒後繼節點 * 注意:若是當前節點的後繼節點爲空,或者是被取消的節點。那就從tail節點逆向遍歷CLH隊列,直至找到一個距離當前節點node最近,且waitStatus<=0的節點,而後喚醒該節點 */ 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) //把該狀態設置成0 compareAndSetWaitStatus(node, ws, 0); /* * 若後繼節點不符合喚醒標準,則逆向遍歷CLH,直至找到一個距離當前節點node最近,且waitStatus<=0的節點 */ Node s = node.next; //找到後繼節點,喚醒後繼節點 if (s == null || s.waitStatus > 0) { //很不巧,後繼節點,節點爲null,或者被取消 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); //喚醒節點 }
1)boolean release(int arg);
獨佔模式釋放資源
/** * 資源的釋放 * 調用tryRelease方法進行釋放鎖 * 釋放鎖成功後,獲取頭節點,接着喚醒後繼節點,調用unparkSuccessor方法 */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
2)boolean tryRelease(int arg);
獨佔模式下嘗試釋放鎖,由子類選擇性實現
protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); }
3)boolean releaseShared(int arg);
共享模式釋放資源
/** * Releases in shared mode. Implemented by unblocking one or more * threads if {@link #tryReleaseShared} returns true. * * @param arg the release argument. This value is conveyed to * {@link #tryReleaseShared} but is otherwise uninterpreted * and can represent anything you like. * @return the value returned from {@link #tryReleaseShared} */ public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false; }
4)boolean tryReleaseShared(int arg);
共享模式下嘗試釋放鎖,由子類選擇性實現
protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
5)int fullyRelease(Node node);
使用當前節點狀態調用release,成功返回狀態,失敗跑出異常
/** * 使用當前節點狀態調用release,成功返回狀態,失敗跑出異常 */ final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } }
/** * Unsafe類實例 */ private static final Unsafe unsafe = Unsafe.getUnsafe(); /** state內存偏移地址 */ private static final long stateOffset; /** head內存偏移地址 */ private static final long headOffset; /** tail內存偏移地址 */ private static final long tailOffset; private static final long waitStatusOffset; /** next內存偏移地址 */ private static final long nextOffset; //靜態初始化塊 static { try { // 獲取偏移量 stateOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("state")); headOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("head")); tailOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); waitStatusOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("waitStatus")); nextOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("next")); } catch (Exception ex) { throw new Error(ex); } } /** * CAS head field. Used only by enq. * 經過原子操做 改變上鎖狀態 * this == null * 第一個參數爲須要改變的對象,第二個爲偏移量(即以前求出來的valueOffset的值),第三個參數爲期待的值,第四個爲更新後的值 */ private final boolean compareAndSetHead(Node update) { //調用本地方法 實現硬件級別的原子操做 cas return unsafe.compareAndSwapObject(this, headOffset, null, update); } /** * CAS tail field. Used only by enq. */ private final boolean compareAndSetTail(Node expect, Node update) { return unsafe.compareAndSwapObject(this, tailOffset, expect, update); } /** * CAS waitStatus field of a node. */ private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update); } /** * CAS next field of a node. */ private static final boolean compareAndSetNext(Node node, Node expect, Node update) { return unsafe.compareAndSwapObject(node, nextOffset, expect, update); }
內部類ConditionObject,它實現了Condition接口,主要用於實現條件鎖。
ConditionObject中也維護了一個隊列,這個隊列主要用於等待條件的成立,當條件成立時,其它線程將signal這個隊列中的元素,將其移動到CLH的隊列中,等待佔有鎖的線程釋放鎖後被喚醒。
Condition典型的運用場景是在BlockingQueue中的實現,當隊列爲空時,獲取元素的線程阻塞在notEmpty條件上,一旦隊列中添加了一個元素,將通知notEmpty條件,將其隊列中的元素移動到AQS隊列中等待被喚醒。
/** * 構造一個條件隊列,來等待條件是否爲真 */ public class ConditionObject implements Condition, java.io.Serializable { /** 版本號 */ private static final long serialVersionUID = 1173984872572414699L; /** First node of condition queue. condition隊列的頭結點 */ private transient Node firstWaiter; /** Last node of condition queue. condition隊列的尾結點 */ private transient Node lastWaiter; /** * Creates a new {@code ConditionObject} instance. * 構造函數 */ public ConditionObject() { } /** * Adds a new waiter to wait queue. * @return its new wait node * 添加新的waiter到wait隊列 */ private Node addConditionWaiter() { //保存尾結點 Node t = lastWaiter; // If lastWaiter is cancelled, clean out. 尾結點不爲空,而且尾結點的狀態不爲CONDITION if (t != null && t.waitStatus != Node.CONDITION) { //清除狀態爲CONDITION的結點 unlinkCancelledWaiters(); //將最後一個結點從新賦值給t t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; }
1)AQS分爲獨佔鎖和共享鎖。 2)AQS分爲CLH自旋隊列和Condition條件隊列。 3)AQS是一個雙向鏈表,由state狀態控制。 4)AQS由volatile修飾保證多線程可見,採用CAS保證原子性。