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