AQS 源碼分析

1.是什么?

全稱:AbstractQueuedSynchronizer

抽象的隊列式的同步器,AQS定義了一套多線程訪問共享資源的同步器框架,許多同步類實現(xiàn)都依賴于它,如常用的ReentrantLock/Semaphore/CountDownLatch...

2.框架


數(shù)據(jù)結構:

? ? ? 1)維護了一個volatile int state

? ? ? 2)先進先出的雙向鏈表,頭節(jié)點為獲取鎖的線程

自定義同步器和AQS

? ? ? AQS頂層已經(jīng)實現(xiàn)了等待隊列的維護(出隊/入隊)

? ? ? 自定義同步器只需要實現(xiàn)共享資源state的獲取和釋放,自定義同步器主要需要實現(xiàn)的方法包括:

? ? ? ? ? 1)isHeldExclusively():該線程是否正在獨占資源。只有用到condition才需要去實現(xiàn)它。

? ? 2) tryAcquire(int):獨占方式。嘗試獲取資源,成功則返回true,失敗則返回false。

? 3) tryRelease(int):獨占方式。嘗試釋放資源,成功則返回true,失敗則返回false。

? ? 4)tryAcquireShared(int):共享方式。嘗試獲取資源。負數(shù)表示失敗;0表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。

? ? 5)tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放后允許喚醒后續(xù)等待結點返回true,否則返回false。

舉例說明:

RetreentLock:state初始化為0,表示未鎖定狀態(tài)。A線程lock()時,會調用tryAcquire()獨占該鎖并將state+1。此后,其他線程再tryAcquire()時就會失敗,直到A線程unlock()到state=0(即釋放鎖)為止,其它線程才有機會獲取該鎖。當然,釋放鎖之前,A線程自己是可以重復獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多么次,這樣才能保證state是能回到零態(tài)的。

? ? ? ? CountDownLatch:任務分為N個子線程去執(zhí)行,state也初始化為N(注意N要與線程個數(shù)一致)。這N個子線程是并行執(zhí)行的,每個子線程執(zhí)行完后countDown()一次,state會CAS減1。等到所有子線程都執(zhí)行完后(即state=0),會unpark()主調用線程,然后主調用線程就會從await()函數(shù)返回,繼續(xù)后余動作。

? ? ? ? 思考:unpark()之后,應該是重新競爭CPU的執(zhí)行權吧?

3.源碼分析

? 按照acquire-release、acquireShared-releaseShared的次序分析AQS頂層源碼

? 3.1 AbstractQueuedSynchronizer#acquire(int i)


? ? ? ? 分析:此方法是獨占模式下線程獲取共享資源的頂層入口。如果獲取到資源,線程直接返回,否則進入等待隊列,直到獲取到資源為止,且整個過程忽略中斷的影響。這也正是lock()的語義,當然不僅僅只限于lock()。獲取到資源后,線程就可以去執(zhí)行其臨界區(qū)代碼了。


? ? ? ? ? AbstractQueuedSynchronizer#tryAcquire()具體資源的獲取交由自定義同步器去實現(xiàn)了(通過state的get/set/CAS),至于能不能重入,能不能加塞,那就看具體的自定義同步器怎么去設計了,自定義同步器在進行資源訪問時要考慮線程安全的影響。


? ? ? ? ? ? 思考:為什么不事先為抽象?

這里之所以沒有定義成abstract,是因為獨占模式下只用實現(xiàn)tryAcquire-tryRelease,而共享模式下只用實現(xiàn)tryAcquireShared-tryReleaseShared。如果都定義成abstract,那么每個模式也要去實現(xiàn)另一模式下的接口。說到底,Doug Lea還是站在咱們開發(fā)者的角度,盡量減少不必要的工作量。


? AbstractQueuedSynchronizer#addWaiter(Node mode),首先以指定的模式構造節(jié)點(共享還是獨占),再嘗試以cas的方式插入隊尾,失敗再使用enq方法插入隊尾。

此處對Node進行解釋:

? ? Node結點是對每一個訪問同步代碼的線程的封裝,其包含了需要同步的線程本身以及線程的狀態(tài)。變量waitStatus則表示當前被封裝成Node結點的等待狀態(tài):

CANCELLED:值為1,在同步隊列中等待的線程等待超時或被中斷,需要從同步隊列中取消該Node的結點,其結點的waitStatus為CANCELLED,即結束狀態(tài),進入該狀態(tài)后的結點將不會再變化。

SIGNAL:值為-1,被標識為該等待喚醒狀態(tài)的后繼結點,當其前繼結點的線程釋放了同步鎖或被取消,將會通知該后繼結點的線程執(zhí)行。說白了,就是處于喚醒狀態(tài),只要前繼結點釋放鎖,就會通知標識為SIGNAL狀態(tài)的后繼結點的線程執(zhí)行。

CONDITION:值為-2,與Condition相關,該標識的結點處于等待隊列中,結點的線程等待在Condition上,當其他線程調用了Condition的signal()方法后,CONDITION狀態(tài)的結點將從等待隊列轉移到同步隊列中,等待獲取同步鎖。

PROPAGATE:值為-3,與共享模式相關,在共享模式中,該狀態(tài)標識結點的線程處于可運行狀態(tài)。

0狀態(tài):值為0,代表初始化狀態(tài)。

AbstractQueuedSynchronizer#enq(Node node),通過自旋的方式設置頭節(jié)點或者尾節(jié)點。


AbstractQueuedSynchronizer#acquireQueued(Node node),該線程獲取資源失敗,已經(jīng)被放入等待隊列尾部了。

? ? ? ? ? 分析:1)如果前驅節(jié)點是頭節(jié)點,則自旋的方式獲取共享資源

? ? ? ? ? ? ? ? ? ? 2)否則進入park當前線程waiting,等待被unpark

安全點:

? ? ? 是否應該park需要根據(jù)AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire(Node pred, Node node)方法判斷,該方法會尋找一個安全點,然后再將當前線程掛起。


? ? ? ? 步驟分析:

? ? ? ? ? ? ? 前置節(jié)點的waitStatus是否為SIGNAL,如果是,則直接掛起;如果不是,繼續(xù)回溯,直到找到SIGNAL狀態(tài)的節(jié)點或者找到一個waitStatus的節(jié)點并CAS的設置為SIGNAL狀態(tài)。

*****? 釋放獨占鎖

*****? 獲取共享鎖

*****? 釋放共享鎖

*********************************

readwritelock的實現(xiàn)方式:

參考:http://www.cnblogs.com/waterystone/p/4920797.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容