AQS

AQS是什么?就是這個(gè)玩意AbstractQueuedSynchronizer

那這個(gè)到底是什么?看到是個(gè)抽象類,看下子類都有什么

看到有ReentrantLock、Semaphore,這和可重入鎖有什么關(guān)系,看下類的注釋,看注釋我只看第一句,嘿嘿嘿,大概意思是實(shí)現(xiàn)阻塞鎖提供了隊(duì)列的性質(zhì),比如semaphore。

那Semaphore是什么?看到j(luò)ava注釋給了代碼demo,稍微改造以下這段代碼為切入點(diǎn),簡(jiǎn)書(shū)帖不了代碼格式的文本,搞半天不行,就截圖吧。

這個(gè)偽代碼的場(chǎng)景是實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池最大連接數(shù)為10,相當(dāng)于做了限制,超過(guò)10就要等待

運(yùn)行結(jié)果

上面涉及到Semaphore的兩個(gè)方法,就以這兩個(gè)方法為切入點(diǎn),不,先看下構(gòu)造器干了什么事情。

有兩個(gè)構(gòu)造器

permits最終賦值給AQS(AbstractQueuedSynchronizer)的屬性state,這個(gè)是AQS的核心屬性,這個(gè)值我們?cè)O(shè)置的為10。

fair表示是否是公平鎖,不傳就是非公平鎖。好接著再來(lái)看這兩個(gè)方法

1)acquire()

這里寫死了1傳進(jìn)去

tryAcquireShared(arg)有兩個(gè)實(shí)現(xiàn),一個(gè)是公平鎖,一個(gè)是不公平鎖。先看下非公平鎖的整體實(shí)現(xiàn)

拿到state-1賦值給remaining,remaining<0直接return,如果remaining>=0,就通過(guò)cas把state修改為remaining。

看完可以知道tryAcquireShared(arg)非公平鎖的實(shí)現(xiàn)就是拿到state-1后的值,如果值小于0直接返回,如果大于等于0就CAS,CAS如果沒(méi)搶到就自旋直到remaining<0返回。嗯。。滴水不漏。。

如果小于0返回執(zhí)行下一個(gè)方法,我們猜測(cè)下下面應(yīng)該如何實(shí)現(xiàn),如果容量(state)被用光了,當(dāng)前線程要么進(jìn)入等待,要么一直CAS(如果這樣明顯不合理),看下Doug Lea是怎么實(shí)現(xiàn)的。

看下addWaiter

用大腿拍下手就只知道這個(gè)enq方法要干啥,初始化(前面判斷了tail不為空的情況,一開(kāi)始肯定為空)和重試入隊(duì)(沒(méi)有入隊(duì)成功就走下來(lái)了)。

那這里有個(gè)問(wèn)題就是第一個(gè)節(jié)點(diǎn)進(jìn)來(lái)的時(shí)候,隊(duì)列長(zhǎng)這個(gè)樣子 ,head是個(gè)空節(jié)點(diǎn),為什么不直接把當(dāng)前節(jié)點(diǎn)作為頭結(jié)點(diǎn)呢?先往后看

再來(lái)接著看doAcquireSharedInterruptibly方法,

這里可以看到當(dāng)前節(jié)點(diǎn)被設(shè)為頭結(jié)點(diǎn)后,又把頭結(jié)點(diǎn)置空,這是為啥呢?難道設(shè)計(jì)成頭結(jié)點(diǎn)為空有什么好處嗎?

結(jié)論:整體看完非公平鎖的acquire()可以知道,非公平鎖也會(huì)入隊(duì),入隊(duì)之后也是重試兩次獲取不到容量就進(jìn)行等待,隊(duì)列中也是頭結(jié)點(diǎn)先進(jìn)行獲取容量(當(dāng)然我是看過(guò)公平鎖的實(shí)現(xiàn)了才用 “也”),只不過(guò)如果有新的線程進(jìn)來(lái)時(shí)是直接獲取容量的(不會(huì)先進(jìn)行入隊(duì))。

上面那個(gè)問(wèn)題嘗試在release()中尋求答案,接著看下release()方法,一看這個(gè)方法沒(méi)有分為公平鎖和非公平鎖,心里一涼。。

tryReleaseShared很簡(jiǎn)單就是把state+1,把之前acquire減掉值還原回去,看下doReleaseShared

看完之后還是不知道為啥要多出來(lái)一個(gè)空的頭結(jié)點(diǎn)。。后續(xù)再研究下。。

至于公平鎖,差異就是上圖這個(gè)方法,主要含義就是多了個(gè)每次取獲取容量的時(shí)候會(huì)判斷是否頭結(jié)點(diǎn)的后繼是否為空,我們知道頭結(jié)點(diǎn)是不參與競(jìng)爭(zhēng)的,也就是頭結(jié)點(diǎn)的后繼是隊(duì)列中的第一個(gè)。這個(gè)方法就是判斷當(dāng)前節(jié)點(diǎn)是不是第一個(gè),第一個(gè)則可以獲取容量,不是則不進(jìn)行獲取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容