AQS框架圖-Java鎖機制-同步器框架

AbstractQueuedSynchronizer是整個java.util.concurrent包的核心。在JDK1.5時引入,該包中的大多數同步器都是基於AQS來構建的。

AQS框架提供了一套通用的機制來管理同步狀態(synchronization state)、阻塞/喚醒線程、管理等待隊列。

我們所熟知的ReentrantLock、CountDownLatch、CyclicBarrier等同步器,其實都是通過內部類實現了AQS框架暴露的API,以此實現各類同步器功能。這些同步器的主要區別其實就是對同步狀態(synchronization state)的定義不同。

其實AbstractQueuedSynchronizer主要就是維護了一個state屬性、一個FIFO隊列和線程的阻塞與解除阻塞操作。state表示同步狀態,它的類型爲32位整型,對state的更新必須要保證原子性。這裏的隊列是一個雙向鏈表,每個節點裏面都有一個prev和next,它們分別是前一個節點和後一個節點的引用。需要注意的是此雙向鏈表除了鏈頭其他每個節點內部都包含一個線程,而鏈頭可以理解爲一個空節點。

鎖的含義

synchronized可以用於獲取實例的鎖。Java的每個實例都持有一個“鎖”,但同一個鎖不可以由兩個以上的線程同時獲取。這種結構是Java編程規範規定的。這是Java語言從一開始就提供的所謂的物理鎖

而AQS提供的鎖與使用synchronized獲取的鎖是不一樣的。這並不是Java編程規範規定的結構。這是所謂的邏輯鎖

1、AQS(AbstractQueuedSynchronizer) 原理圖

2、AQS框架

 

3、Node結構

4、首個獲取鎖的線程,AQS中的等待隊列還是空。

5、當AQS隊列爲空的時候,先創建一個dummy頭結點

6、進入下一次循環,插入隊尾結點。(因爲併發插入的情況存在,所以該方法設計成了自旋操作)

7、插入完ThreadB後,隊列的初始狀態如下:

8、雖然ThreadB是隊首結點,但是它拿不到鎖(被ThreadA佔有着),所以ThreadB會阻塞,但在阻塞前需要設置下前驅的狀態,以便將來可以喚醒我:

9、添加ThreadC的過程和ThreadB完全一樣,同樣拿不到鎖,然後加入到等待隊列隊尾

10、

11、同步隊列是AQS很重要的組成部分,它是一個雙端隊列,遵循FIFO原則,主要作用是用來存放在鎖上阻塞的線程,當一個線程嘗試獲取鎖時,如果已經被佔用,那麼當前線程就會被構造成一個Node節點假如到同步隊列的尾部

12、隊列的頭節點是成功獲取鎖的節點,當頭節點線程是否鎖時,會喚醒後面的節點並釋放當前頭節點的引用。 

13、獨佔鎖的獲取和釋放流程

14、自旋鎖

15、CLH

16、

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章