1. 管程 — Java同步的設計思想
管程:指的是管理共享變量以及對共享變量的操作過程,讓他們支援并發。
互斥:同一時刻隻允許一個線程通路共享資源;
同步:線程之間如何通信、協作。
MESA模型
在管程的發展史上,先後出現過三種不同的管程模型,分别是Hasen模型、Hoare模型和MESA模型。現在正在廣泛使用的是MESA模型。
管程中引入了條件變量的概念,而且每個條件變量都對應有一個等待隊列。條件變量和等待隊列的作用是解決線程之間的同步問題。
Java中針對管程有兩種實作
- 一種是基于Object的Monitor機制,用于synchronized内置鎖的實作
- 一種是抽象隊列同步器AQS,用于JUC包下Lock鎖機制的實作
2. AQS原理分析
2.1 什麼是AQS
java.util.concurrent包中的大多數同步器實作都是圍繞着共同的基礎行為,比如等待隊列、條件隊列、獨占擷取、共享擷取等,而這些行為的抽象就是基于AbstractQueuedSynchronizer(簡稱AQS)實作的,AQS是一個抽象同步架構,可以用來實作一個依賴狀态的同步器。
JDK中提供的大多數的同步器如Lock, Latch, Barrier等,都是基于AQS架構來實作的
- 一般是通過一個内部類Sync繼承 AQS
- 将同步器所有調用都映射到Sync對應的方法
AQS具備的特性:
- 阻塞等待隊列
- 共享/獨占
- 公平/非公平
- 可重入
- 允許中斷
2.2 AQS核心結構
AQS内部維護屬性volatile int state
- state表示資源的可用狀态
State三種通路方式:
- getState()
- setState()
- compareAndSetState()
定義了兩種資源通路方式:
- Exclusive-獨占,隻有一個線程能執行,如ReentrantLock
- Share-共享,多個線程可以同時執行,如Semaphore/CountDownLatch
AQS實作時主要實作以下幾種方法:
- isHeldExclusively():該線程是否正在獨占資源。隻有用到condition才需要去實作它。
- tryAcquire(int):獨占方式。嘗試擷取資源,成功則傳回true,失敗則傳回false。
- tryRelease(int):獨占方式。嘗試釋放資源,成功則傳回true,失敗則傳回false。
- tryAcquireShared(int):共享方式。嘗試擷取資源。負數表示失敗;0表示成功,但沒有剩餘可用資源;正數表示成功,且有剩餘資源。
- tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放後允許喚醒後續等待結點傳回true,否則傳回false。
2.3 AQS定義兩種隊列
- 同步等待隊列: 主要用于維護擷取鎖失敗時入隊的線程。
- 條件等待隊列: 調用await()的時候會釋放鎖,然後線程會加入到條件隊列,調用signal()喚醒的時候會把條件隊列中的線程節點移動到同步隊列中,等待再次獲得鎖。
AQS 定義了5個隊列中節點狀态:
- 值為0,初始化狀态,表示目前節點在sync隊列中,等待着擷取鎖。
- CANCELLED,值為1,表示目前的線程被取消;
- SIGNAL,值為-1,表示目前節點的後繼節點包含的線程需要運作,也就是unpark;
- CONDITION,值為-2,表示目前節點在等待condition,也就是在condition隊列中;
- PROPAGATE,值為-3,表示目前場景下後續的acquireShared能夠得以執行;
同步等待隊列
AQS當中的同步等待隊列也稱CLH隊列,CLH隊列是Craig、Landin、Hagersten三人發明的一種基于雙向連結清單資料結構的隊列,是FIFO先進先出線程等待隊列,Java中的CLH隊列是原CLH隊列的一個變種,線程由原自旋機制改為阻塞機制。
AQS 依賴CLH同步隊列來完成同步狀态的管理:
- 目前線程如果擷取同步狀态失敗時,AQS則會将目前線程已經等待狀态等資訊構造成一個節點(Node)并将其加入到CLH同步隊列,同時會阻塞目前線程
- 當同步狀态釋放時,會把首節點喚醒(公平鎖),使其再次嘗試擷取同步狀态。
- 通過signal或signalAll将條件隊列中的節點轉移到同步隊列。(由條件隊列轉化為同步隊列)
條件等待隊列
AQS中條件隊列是使用單向清單儲存的,用nextWaiter來連接配接:
- 調用await方法阻塞線程;
- 目前線程存在于同步隊列的頭結點,調用await方法進行阻塞(從同步隊列轉化到條件隊列)
3. ReentrantLock源碼分析
ReentrantLock是一種基于AQS架構的應用實作,是JDK中的一種線程并發通路的同步手段,它的功能類似于synchronized是一種互斥鎖,可以保證線程安全。
ReentrantLock基本使用方式
源碼閱讀過程中要關注的問題
1.公平和非公平鎖,可重入鎖是如何實作的
2.設計的精髓:并發場景下入隊和出隊操作是如何設計的
- 線程競争鎖失敗入隊阻塞邏輯實作
- 釋放鎖的線程喚醒阻塞線程出隊競争鎖的邏輯實作
結合課上源碼分析流程圖了解ReentrantLock的實作