技術分享之AQS——內容提要


1. 背景

最近團隊內部技術分享,我做了個關於AQS的分享。ppt中涵蓋的部分要點內容,現在整理到博客上。
關於AQS本身的源碼解讀,可以參考我之前的博文

2. 要點梳理

下面是一些技術分享的要點梳理。

2.1 LockSupport的實現

AQS中的阻塞/喚醒最終是基於LockSupport的park/unpark實現的。那么park和unpark又是怎么實現的呢?


對於Mac OS,我們主要調試os_bsd.cpp,以上截圖取自os_bsd.cpp

我們通過調試JVM可以看到LockSupport中調用的UNSAFE#park最終會通過調用pthread_cond_wait實現阻塞。
而喚醒是通過pthread_cond_signal實現的。

在JVM中每個線程有個自己的Parker類,對一個線程進行阻塞/喚醒操作需要獲取到線程Parker對應的互斥鎖,Parker內部有個計數器,取值為0和1,調用unpark會置計數器為1.

因此在Java程序中,如果先unpark線程A,再park線程A,線程不會阻塞;但是如果unpark兩次,再park兩次,線程會阻塞。

2.2 Lock語義實現

java.util.concurrent.locks.lock接口寫清了鎖的實現必須保證的內存語義。

我們舉一個例子:

以上代碼截圖自java.util.concurrent.ArrayBlockingQueue

JUC中的ArrayBlockingQueue是基於單鎖保護的阻塞隊列,其中一些關鍵的共享變量並沒有使用volatile關鍵字,原因是ArrayBlockingQueue的操作使用了同一把ReentrantLock來保護,因為Lock的內存語義保證,ArrayBlockingQueue中的這些共享變量不需要使用volatile保證可見性

那么就ReentrantLock為例,它是如何實現的呢?我們知道ReentrantLock內部組合了一個Sync類,Sync類繼承了AQS,ReentrantLock將Lock本身的API委托給Sync(子類)處理。

其奧秘就是AQS中的state變量,它被volatile修飾。

AQS#setState: 具有volatile寫語義,AQS#getState: 具有volatile讀語義,而AQS#compareAndSetState: 具有volatile讀與寫語義。

我們以非公平鎖ReentrantLock#NonfairSync為例:

這是lock方法的實現,我們可以看到
如果線程通過CAS state進入臨界區,那么在進入臨界區前的一步操作便是一個具有volatile讀寫語義的操作。

如上展示的是另一種獲取獨占鎖進入臨界區的路徑。

可以看到仍然是一個具有volatile讀寫語義的操作。

那么以釋放鎖為例:

在出臨界區的過程中使用了setState,這是一個volatile寫語義的操作。

我們可以看到整個獨占鎖的獲取和釋放都被一對volatile讀和volatile寫語義的操作包着


根據happens-before傳遞性,線程A釋放鎖,線程B獲得鎖后,線程A所有可見的共享變量,對於線程B都可見。

可以說ReentrantLock對Lock內存語義的實現便是基於對AQS的volatile state的操作

2.3 共享鎖中PROPAGATE狀態的意義

市面上的書籍或者網上的資料基本都對節點的PROPAGATE狀態的意義簡略帶過。
而實際上在AQS中共享模式下的喚醒,僅僅依賴tryAcquireShared返回的int值是不夠的,此狀態拓展了釋放后繼線程的條件,保證共享模式下線程喚醒行為傳播下去。
可以翻翻Doug Lea網站上當時的代碼提交記錄,可以看到此狀態的引入是為了修復一個在共享鎖並發釋放情況下潛在的線程hang住問題。此問題更多的細節,可以參考我之前的博文

2.4 一些重要的斷言

  • head節點絕對不會是CANCELLED
  • 一個節點的前驅為head,不代表鎖正被占用,而是代表當前節點有可能可以成功獲取到鎖
  • 一個節點的后繼為null,不代表這個節點就是tail
  • tryRelease的語義是在完全釋放獨占鎖時才返回true

2.5 如何調試AQS

想不明白的地方想改代碼調試,怎么辦?
拷出來改,然后再拷個ReentrantLock、Semaphore啥的調調吧
注意Unsafe這個東西用戶代碼直接拿實例會出SecurityException,需要改一下拷出來的AQS代碼,用反射拿Unsafe。

2.6 如何琢磨AQS

  • 琢磨並發程序設計需要有一定時空想象力,把自己大腦當成一個線程調度器吧。
  • Doug Lea老爺子的網站上寶貝很多
  • 網上文章質量參差不齊,關鍵要有自己理解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM