知識(shí)點(diǎn)
AQS維護(hù)著兩個(gè)隊(duì)列:
- 一個(gè)是由AQS類(lèi)維護(hù)的CLH隊(duì)列(用于運(yùn)行CLH算法)
- 另一個(gè)是由AQS的內(nèi)部類(lèi)ConditionObject維護(hù)的Condition隊(duì)列(用于支持線(xiàn)程間的同步出爹,提供await,signal,signalAll方法)脂信。
關(guān)于鎖
- 鎖的釋放:通過(guò)持有鎖的線(xiàn)程對(duì)CLH隊(duì)列的下個(gè)節(jié)點(diǎn)調(diào)用
LockSupport.unpark(s.thread);
- 加鎖:調(diào)用
LockSupport.park(this);
將本線(xiàn)程阻塞
Node.SIGNAL
有2個(gè)作用:
- 前繼節(jié)點(diǎn)為
SIGNAL
時(shí),后繼節(jié)點(diǎn)會(huì)被掛起- 前繼節(jié)點(diǎn)釋放鎖或被取消之后师抄,必須喚醒(unparking)其后繼結(jié)點(diǎn)
共享模式和獨(dú)占模式在代碼上的區(qū)分點(diǎn):
doAcquireShared(int arg)中:
int r = tryAcquireShared(arg); //r說(shuō)明可以多線(xiàn)程共享鎖
setHeadAndPropagate(node, r); //顯示當(dāng)本節(jié)點(diǎn)獲得鎖后霹娄,還要通知后續(xù)節(jié)點(diǎn)繼續(xù)獲取鎖
AQS中對(duì)CLH算法的實(shí)現(xiàn)與標(biāo)準(zhǔn)的CLH算法有什么異同翎苫?
到這里已經(jīng)可以解答這個(gè)問(wèn)題了兔院。AQS到底在哪些地方變種
CLH鎖算法姿鸿?
- CLH是一種自旋鎖算法(在得到鎖之前會(huì)不停地自旋)谆吴,而AQS會(huì)在幾次自旋失敗后就將線(xiàn)程阻塞,這是為了避免不必要地占用CPU苛预;
- CLH是自旋在前繼節(jié)點(diǎn)的標(biāo)志位上的句狼,而AQS是自旋在
p == head
上面(即不停地判斷前繼節(jié)點(diǎn)是否是頭節(jié)點(diǎn)),只有在發(fā)現(xiàn)前繼節(jié)點(diǎn)是頭節(jié)點(diǎn)時(shí)热某,才會(huì)通過(guò)tryAcquire
嘗試獲得鎖腻菇,這里有一個(gè)比較另我困惑的地方,就是head是一個(gè)volatile的全局引用昔馋,這么做的話(huà)顯然違背了CLH鎖的Local Spin的思想芜繁,具體原因未知,可能是因?yàn)锳QS最初就是被設(shè)計(jì)為阻塞的同步器而不是自旋鎖吧绒极。
Condition
Node類(lèi)的nextWaiter
字段其實(shí)是用來(lái)存放Condition隊(duì)列的后繼的骏令,要和next
字段(用來(lái)存放CLH隊(duì)列后繼)進(jìn)行區(qū)分。
之所以Condition隊(duì)列和CLH隊(duì)列都采用Node類(lèi)作為節(jié)點(diǎn)的原因就是為了方便將節(jié)點(diǎn)從Condition隊(duì)列搬運(yùn)到CLH隊(duì)列垄提。