摘要:作用是存儲獲取鎖失敗的阻塞線程。獨占模式下,鎖是線程獨占的,而共享模式下,鎖是可以被多個線程占用的。等方法就是讓線程阻塞加入隊列喚醒線程等。該方法其實就是自旋嘗試獲取鎖或阻塞線程子類實現(xiàn)決定。
AQS,全稱AbstractQueuedSynchronizer,是Concurrent包鎖的核心,沒有AQS就沒有Java的Concurrent包。它到底是個什么,我們來看看源碼的第一段注解是怎么說明
看完第一段,總結(jié)下
AQS是一個同步的基礎(chǔ)框架,基于一個先進(jìn)先出的隊列。
鎖機(jī)制基于一個狀態(tài)值,它是原子值。
AQS的子類負(fù)責(zé)定義與操作這個狀態(tài)值,但必須通過AQS提供的原子操作
AQS剩余的方法就是圍繞隊列,與線程阻塞喚醒等功能
基于以上概念,我們看看源碼到底是這么實現(xiàn)這些功能的
AQS的成員變量 stateprivate volatile int state;
該變量標(biāo)記為volatile,說明該變量是對所有線程可見的。作用在于每個線程改變該值,都會馬上讓其他線程可見,在CAS(可見鎖概念與鎖優(yōu)化)的時候是必不可少的。在AQS類中,不會直接操作這個值,而是交由它的子類去操作和定義他的作用。
AQS中有一個靜態(tài)內(nèi)部類Node,其實現(xiàn)是一個雙向鏈表。head與tail則是這個鏈表的頭尾指針。作用是存儲獲取鎖失敗的阻塞線程。同樣的,這個鏈表是會被多個線程操作的,所以它里面的變量多是被標(biāo)記為volatile,并且操作也要通過CAS等原子方法去執(zhí)行。
Node還有一個模式的屬性:獨占模式和共享模式。獨占模式下,鎖是線程獨占的,而共享模式下,鎖是可以被多個線程占用的。
對于大多數(shù)需要操作的原子屬性,都對應(yīng)會有一個大寫的值,它的類是VarHandler。例如state、head、tail都有對應(yīng)的VarHandler,STATE、HEAD、TAIL。VarHandler是1.9的新特性,提供了類似于原子操作以及Unsafe操作的功能,里面的原子操作大多是native方法,比較難查看源碼。
條件隊列,是AQS中一個非常關(guān)鍵內(nèi)部類。這個名字起非常奇異,讓人搞不懂,看它類注釋也看不懂說了什么。看看AQS頭部注解
這個類是為了讓子類支持獨占模式的。深入看其中的源碼實現(xiàn),其實就是Node在功能性上的封裝,最終讓子類實現(xiàn)讓當(dāng)前線程怎么獨占一個Object鎖。await()、dosign()等方法就是讓線程阻塞、加入隊列、喚醒線程等。AQS框架下基本各種獨占的加鎖,解鎖等操作到最后都是基于這個類實現(xiàn)的。該類是提供給子類去使用的,具體實現(xiàn)等下次說ReentranLock再深入了解。有人可能覺得為什么實現(xiàn)這個內(nèi)部類,又不用,而是給子類去用,那為什么不放到子類去呢?其實答案,很簡單,抽象加模板模式。
p.s. 只有獨占鎖才能配合該類使用。
AQS的公用的方法,主要是加鎖與解鎖方法。以下方法只提供了模板,部分實現(xiàn)還是在子類當(dāng)中,直接調(diào)用會拋出異常。
acquire()嘗試獲取鎖,失敗則進(jìn)入隊列。
先執(zhí)行tryAcquire()(子類實現(xiàn)),成功則直接返回,如果是獲取鎖失敗,則執(zhí)行addWaiter(),通過CAS在雙向鏈表的尾部添加一個新獨占節(jié)點。
然后把節(jié)點丟到acquireQueued()中執(zhí)行。該方法其實就是自旋嘗試獲取鎖或阻塞線程(子類實現(xiàn)決定)。一開始,獲取新節(jié)點的前驅(qū)節(jié)點,如果這個節(jié)點是head,則證明只有兩個節(jié)點,此時再次執(zhí)行tryAcquire()嘗試獲取鎖,若獲取成功,則不需要中斷,成功結(jié)束。
如果還是獲取失敗,則執(zhí)行shouldParkAfterFailedAcquire(),根據(jù)前驅(qū)節(jié)點狀態(tài)(子類設(shè)值)判斷是否繼續(xù)自旋(當(dāng)waitStatus為初始值,重復(fù)上一步,直到前面的節(jié)點一直在減少到前驅(qū)節(jié)點為head)或者阻塞線程(當(dāng)waitStatus標(biāo)記為SIGNAL)
最后如果acquireQueued()返回需要阻塞,則執(zhí)行selfInterrupt()設(shè)置線程為中斷
可以看回acquire()函數(shù)的寫法,十分的藝術(shù)。利用條件判斷的短路規(guī)則,實現(xiàn)在if()條件內(nèi)嵌套判斷執(zhí)行語音。一般人(筆者本人)如果要實現(xiàn)這個功能,會這么寫
所以下次遇到類似嵌套if條件判斷的語句,可以學(xué)習(xí)下acquire()的這種短路寫法。贊
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76934.html
摘要:注意是一個假節(jié)點,阻塞的節(jié)點是作為后面的節(jié)點出現(xiàn)的。總之在非公平鎖場景下嘗試去獲取鎖,如果獲取上了,則置一下狀態(tài),并設(shè)置自己為獨占線程,并支持重入鎖功能。方法用于創(chuàng)建一個節(jié)點值為當(dāng)前線程并維護(hù)一個雙向鏈表。阻塞了當(dāng)前線程。 部分段落來自于http://javadoop.com/post/Abst...,他的文章相當(dāng)不錯。 ReentrantLock基于Sync內(nèi)部類來完成鎖。Sync繼...
摘要:二什么是重入鎖可重入鎖,顧名思義,支持重新進(jìn)入的鎖,其表示該鎖能支持一個線程對資源的重復(fù)加鎖。將由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。可以使用和方法來檢查此情況是否發(fā)生。 一、寫在前面 前幾篇我們具體的聊了AQS原理以及底層源碼的實現(xiàn),具體參見 《J.U.C|一文搞懂AQS》《J.U.C|同步隊列(CLH)》《J.U.C|AQS獨占式源碼分析》《J.U.C|AQS共享式源...
摘要:前置文章為,如果不了解的基本和實現(xiàn)機(jī)制,建議先看一下這個文章。類似于和,常用于實現(xiàn)生產(chǎn)者消費者。以下代碼是一個用的做的一個生產(chǎn)者消費者例子。 前置文章為https://segmentfault.com/a/11...,如果不了解AQS的基本lock和unlock實現(xiàn)機(jī)制,建議先看一下這個文章。 Condition類似于wait和notify,notifyAll,常用于實現(xiàn)生產(chǎn)者消費者。...
摘要:關(guān)于,最后有兩點規(guī)律需要注意當(dāng)?shù)牡却犃嘘犑捉Y(jié)點是共享結(jié)點,說明當(dāng)前寫鎖被占用,當(dāng)寫鎖釋放時,會以傳播的方式喚醒頭結(jié)點之后緊鄰的各個共享結(jié)點。當(dāng)?shù)牡却犃嘘犑捉Y(jié)點是獨占結(jié)點,說明當(dāng)前讀鎖被使用,當(dāng)讀鎖釋放歸零后,會喚醒隊首的獨占結(jié)點。 showImg(https://segmentfault.com/img/remote/1460000016012293); 本文首發(fā)于一世流云的專欄:...
摘要:關(guān)于接口的介紹,可以參見多線程進(jìn)階二鎖框架接口。最終線程釋放了鎖,并進(jìn)入阻塞狀態(tài)。當(dāng)線程被通知喚醒時,則是將條件隊列中的結(jié)點轉(zhuǎn)換成等待隊列中的結(jié)點,之后的處理就和獨占功能完全一樣。 showImg(https://segmentfault.com/img/remote/1460000016012490); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/bl...
閱讀 843·2021-11-24 10:44
閱讀 2778·2021-11-11 16:54
閱讀 3159·2021-10-08 10:21
閱讀 2066·2021-08-25 09:39
閱讀 2899·2019-08-30 15:56
閱讀 3459·2019-08-30 13:46
閱讀 3493·2019-08-23 18:09
閱讀 2066·2019-08-23 17:05