【JDK源碼分析系列】AbstractQueuedSynchronizer 源碼分析 -- 基本屬性
【1】AbstractQueuedSynchronizer 整體架構
1. AQS 中隊列只有兩個 : 同步隊列 + 條件隊列,底層數據結構兩者都是鏈表
2. 圖中有四種顏色的線代表四種不同的場景,1、2、3 序號代表看的順序
【2】AbstractQueuedSynchronizer 基本屬性
【2.0】AbstractQueuedSynchronizer 的定義與說明
// 1. 提供了一種框架,自定義了先進先出的同步隊列,讓獲取不到鎖的線程能進入同步隊列中排隊;
// 2. 同步器有個狀態字段,可以通過狀態字段來判斷能否得到鎖,此時設計的關鍵在於依賴安全的 atomic value 來表示狀態
// (雖然註釋是這個意思,但實際上是通過把狀態聲明爲 volatile,在鎖裏面修改狀態值來保證線程安全的);
// 3. 子類可以通過給狀態 CAS 賦值來決定能否拿到鎖,可以定義那些狀態可以獲得鎖,哪些狀態表示獲取不到鎖
// (比如定義狀態值是 0 可以獲得鎖,狀態值是 1 就獲取不到鎖);
// 4. 子類可以新建非 public 的內部類,用內部類來繼承 AQS,從而實現鎖的功能;
// 5. AQS 提供了排它模式和共享模式兩種鎖模式,排它模式下:只有一個線程可以獲得鎖,
// 共享模式可以讓多個線程獲得鎖,子類 ReadWriteLock 實現了兩種模式;
// 6. 內部類 ConditionObject 可以被用作 Condition,通過 new ConditionObject () 即可得到條件隊列;
// 7. AQS 實現了鎖、排隊、鎖隊列等框架,至於如何獲得鎖、釋放鎖的代碼並沒有實現,
// 比如 tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared、isHeldExclusively 這些方法,
// AQS 中默認拋 UnsupportedOperationException 異常,都是需要子類去實現的;
// 8. AQS 繼承 AbstractOwnableSynchronizer 是爲了方便跟蹤獲得鎖的線程,可以幫助監控和診斷工具識別是哪些線程持有了鎖;
// 9. AQS 同步隊列和條件隊列,獲取不到鎖的節點在入隊時是先進先出,但被喚醒時,可能並不會按照先進先出的順序執行;
// AQS 是個抽象類,就是給各種鎖子類繼承用的,AQS 定義了很多如何獲得鎖,如何釋放鎖的抽象方法,目的就是爲了讓子類去實現;
// 繼承了 AbstractOwnableSynchronizer,AbstractOwnableSynchronizer 的作用
// 就是爲了知道當前是那個線程獲得了鎖,方便監控用的;
// AbstractOwnableSynchronizer 類中 private transient Thread exclusiveOwnerThread; 屬性用於描述當前獲得鎖的線程
// setExclusiveOwnerThread 方法用於設置當前獲取鎖的線程
// protected final void setExclusiveOwnerThread(Thread thread) {
// exclusiveOwnerThread = thread;
// }
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
【2.1】AbstractQueuedSynchronizer 簡單屬性
// 同步器的狀態,根據當前狀態進行判斷是否可以獲得當前鎖
// 如果當前state是0,那麼可以獲得鎖
// 可重入鎖,每次獲得鎖+1,每次釋放鎖-1
private volatile int state;
// 自旋超時閥值,單位納秒
// 當設置等待時間時纔會用到這個屬性
static final long spinForTimeoutThreshold = 1000L;
【2.2】AbstractQueuedSynchronizer 同步隊列屬性
同步隊列:底層數據結構是一個雙向鏈表,當多個線程都來請求鎖時,某一時刻有且只有一個線程能夠獲得鎖 (排它鎖),那麼剩餘獲取不到鎖的線程,都會到同步隊列中去排隊並阻塞自己,當有線程主動釋放鎖時,就會從同步隊列頭開始釋放一個排隊的線程,讓線程重新去競爭鎖,所以同步隊列的主要作用阻塞獲取不到鎖的線程,並在適當時機釋放這些線程。
// 同步隊列的頭。
// 公平的鎖先入先出。
private transient volatile Node head;
// 等待隊列的尾
private transient volatile Node tail;
【2.3】AbstractQueuedSynchronizer 條件隊列屬性
條件隊列:條件隊列管理獲取不到鎖的線程,底層數據結構也是鏈表隊列,但條件隊列不直接和鎖打交道,但常常和鎖配合使用,是一定的場景下,對鎖功能的一種補充。
private static final long serialVersionUID = 1173984872572414699L;
// 條件隊列中第一個 node
private transient Node firstWaiter;
// 條件隊列中最後一個 node
private transient Node lastWaiter;
【2.4】AbstractQueuedSynchronizer Node 屬性
//Node 既是同步隊列的節點,又是條件隊列的節點,
//在入隊的時候,用 Node 把線程包裝一下,然後把 Node 放入兩個隊列中
static final class Node {
//node 是共享模式
/** 標誌用於指示一個節點在共享模式下等待 */
static final Node SHARED = new Node();
//node 是排它模式
/** 標誌用於指示一個節點在獨佔模式下等待 */
static final Node EXCLUSIVE = null;
/**
* 等待狀態值,表示線程被取消
*
* 由於在同步隊列中等待的線程等待超時或中斷,需要從同步隊列中取消等待
* 節點進入該狀態後不會發生變化
*/
// 被取消
static final int CANCELLED = 1;
/**
* 後繼結點的線程處於等待狀態,而當前節點的線程如果釋放了同步狀態或者被取消,
* 將會通知後繼節點,使後繼節點的線程得以運行
*/
// SIGNAL 狀態的意義:同步隊列中的節點在自旋獲取鎖的時候,
// 如果前一個節點的狀態是 SIGNAL,那麼自己就可以阻塞休息了,否則自己一直自旋嘗試獲得鎖
static final int SIGNAL = -1;
/**
* 節點在等待隊列中,節點線程等待在Condition上,
* 當其他線程對Condition調用了Signal()方法後,
* 該節點將會從等待隊列轉移到同步隊列中,加入到對同步狀態的獲取中
*/
// 表示當前 node 正在條件隊列中,
// 當有節點從同步隊列轉移到條件隊列時,狀態就會被更改成 CONDITION
static final int CONDITION = -2;
/**
* 表示下一次共享式同步狀態獲取將會無條件地被傳播下去
*/
// 無條件傳播,共享模式下,該狀態的進程處於可運行狀態
static final int PROPAGATE = -3;
/**
* 等待狀態變量
*
* volatile 作用簡介 : java 線程內存模型將確保所有線程看到的該變量是一致的;
*/
// 表示當前節點的狀態,通過節點的狀態來控制節點的行爲
// 普通同步節點,就是 0 ,條件節點是 CONDITION -2
volatile int waitStatus;
/**
* 指向同步隊列中當前節點的前驅節點
*/
// 當前節點的前節點
// 節點 acquire 成功後就會變成 head
// head 節點不能被 cancelled
volatile Node prev;
/**
* 指向同步隊列中當前節點的後繼節點
*/
// 當前節點的下一個節點
volatile Node next;
// 當前節點的線程
volatile Thread thread;
// 在同步隊列中,nextWaiter 並不真的是指向其下一個節點,我們用 next 表示同步隊列的下一個節點,
// nextWaiter 只是表示當前 Node 是排它模式還是共享模式
// 但在條件隊列中,nextWaiter 就是表示下一個節點元素
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 的默認構造方法
*
* 用於創立初始化頭結點或者共享節點
*/
Node() {
}
/**
* 內部類 Node 的構造方法
*
* 構造的節點指定等待隊列中的節點
*/
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
/**
* 內部類 Node 的構造方法
*
* 構造的節點指定等待的狀態
*/
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
【2.5】AbstractQueuedSynchronizer 一般方法
【2.5.0】AbstractQueuedSynchronizer 隊列操作圖示
【2.5.1】AbstractQueuedSynchronizer 相關 CAS 方法
/**
* CAS 方式設置同步狀態;
*/
protected final boolean compareAndSetState(int expect, int update) {
/**
* Unsafe 類提供了硬件級別的原子操作,提供了一些繞開JVM的更底層功能,由此提高效率;
* compareAndSwapInt : 比較並交換 int 型變量
*
* 參數說明
* 參數包含 : 需要讀寫的內存位置(stateOffset)、進行比較的預期原值(expect)
* 和擬寫入的新值(update);
* 處理方式 : 如果內存位置stateOffset的值與預期原值expect相匹配,
* 那麼處理器會自動將該位置值更新爲新值update;
* 否則處理器不做任何操作。
*/
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
/**
* CAS head field. Used only by enq.
*/
private final boolean compareAndSetHead(Node update) {
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);
}
【2.5.2】AbstractQueuedSynchronizer 相關線程處理方法
private final boolean parkAndCheckInterrupt() {
//阻塞當前線程
LockSupport.park(this);
//中斷當前線程
return Thread.interrupted();
}
【3】條件 (Condition)
【3.0】Condition 的定義與說明
// 1. 當 lock 代替 synchronized 來加鎖時,Condition 就可以用來代替 Object 中相應的監控方法了,
// 比如 Object#wait ()、Object#notify、Object#notifyAll 這些方法
// 2. 提供了一種線程協作方式:一個線程被暫停執行,直到被其它線程喚醒
// 3. Condition 實例是綁定在鎖上的,通過 Lock#newCondition 方法可以產生該實例
// 4. 除了特殊說明外,任意空值作爲方法的入參,都會拋出空指針
// 5. Condition 提供了明確的語義和行爲,這點和 Object 監控方法不同
public interface Condition {
【3.1】Object 的監視器方法與 Condition 接口對比
【3.2】Condition 常用方法以及描述
參考致謝
本博客爲博主的學習實踐總結,並參考了衆多博主的博文,在此表示感謝,博主若有不足之處,請批評指正。
【1】Java併發編程的藝術