Java中的併發包,是在Java代碼中併發程序的熱門話題。若是咱們去讀concurrent包的源碼時,會發現其真正的核心是 AbstractQueuedSynchronizer , 簡稱 AQS 框架 , 而 Doug Lea 大神正是此包的做者。java
以前也看過一遍 AbstractQueuedSynchronize,但印象不深,只有依稀的印象。此次從新學習一遍,並整理出筆記,但願對本身或者是別人有用。固然了,筆者也是淺顯的過一遍,不少細節也並非徹底理解。併發
建議讀者先看這個系列的文章:Inside AbstractQueuedSynchronizer,以後再繼續本篇。框架
首先,AQS會對進行 acquire 而被阻塞的線程進行管理,說是管理,其實就是內部維護了一個FIFO隊列,這個隊列是一個雙向鏈表。鏈頭能夠理解爲是一個空的節點,除了鏈頭之外,每一個節點內部都持有着一個線程,同時,有着兩個重要的字段:waitStatus 和 nextWaiter。nextWaiter通常是做用與在使用Condition時的隊列。而waitStatus則有如下幾個字段:ide
SIGNAL 表示下一個節點應該被喚醒。爲何是下一個節點?由於剛剛說了,這個FIFO隊列,鏈頭都是一個空的節點,但此節點的 waitStatus 正好就表示了要對下一節點作的事情學習
CANCELLED 表示此節點持有的線程被中斷,或者該線程爲null了。節點只能是暫時停留在此狀態,由於在線程進入AQS時,線程會找機會整理鏈表,包括刪除CANCELLED狀態的節點。優化
CONDITION 表示此節點是在另外一個隊列中 —— condition隊列中。好比咱們使用的ReentrantLock.newCondition()得到Condition對象進行await時,在AQS內部所產生的節點。ui
PROPAGATE 顧名思義,傳播。這點比較難理解,須要仔細推敲。由於此狀態是爲共享同步器使用的。加入此狀態,能夠避免無謂的線程 park 和 unpark。按照我對代碼的理解,這是對多個線程併發獲取共享同步器(好比acquireShared)所進行的優化,至少有3個線程併發,但想要優化效果明顯的話,可能須要幾十個線程併發的獲取共享同步器(好比acquireShared),若是在併發量很是大的時候,對系統的吞吐量的做用應該很多。線程
AbstractQueuedSynchronizer內置一個state字段,用來表示某種意義——當ReentrantLock使用AQS的時候,state被用來表示鎖被重入的次數;當’Semaphore’使用AQS的時候,state則被用來表示當前還有多少信號量可被獲取。code
AbstractQueuedSynchronizer 支持兩種模式,分別是獨佔式和共享式。二者進行獲取和釋放動做的思路都是差很少的。對象
獲取同步器的流程以下:
<!-- lang: java --> if(嘗試獲取成功){ return; }else{ 加入等待隊列;park本身 }
釋放同步器的流程以下:
<!-- lang: java --> if(嘗試釋放成功){ unpark等待隊列中第一個節點 }else{ return false }
只要環繞着這兩個思路去看AQS中的代碼,相信應該能夠明白其中的主要原理。