AQS原理

知識點

AQS維護著兩個隊列:

  • 一個是由AQS類維護的CLH隊列(用于運行CLH算法)
  • 另一個是由AQS的內(nèi)部類ConditionObject維護的Condition隊列(用于支持線程間的同步,提供await,signal,signalAll方法)。

關(guān)于鎖

  • 鎖的釋放:通過持有鎖的線程對CLH隊列的下個節(jié)點調(diào)用LockSupport.unpark(s.thread);
  • 加鎖:調(diào)用LockSupport.park(this);將本線程阻塞

Node.SIGNAL有2個作用:

  • 前繼節(jié)點為SIGNAL時,后繼節(jié)點會被掛起
  • 前繼節(jié)點釋放鎖或被取消之后,必須喚醒(unparking)其后繼結(jié)點

共享模式和獨占模式在代碼上的區(qū)分點:

doAcquireShared(int arg)中:
int r = tryAcquireShared(arg);  //r說明可以多線程共享鎖
setHeadAndPropagate(node, r);  //顯示當(dāng)本節(jié)點獲得鎖后,還要通知后續(xù)節(jié)點繼續(xù)獲取鎖

AQS中對CLH算法的實現(xiàn)與標(biāo)準(zhǔn)的CLH算法有什么異同?

到這里已經(jīng)可以解答這個問題了。AQS到底在哪些地方變種CLH鎖算法?

  • CLH是一種自旋鎖算法(在得到鎖之前會不停地自旋),而AQS會在幾次自旋失敗后就將線程阻塞,這是為了避免不必要地占用CPU;
  • CLH是自旋在前繼節(jié)點的標(biāo)志位上的,而AQS是自旋在p == head上面(即不停地判斷前繼節(jié)點是否是頭節(jié)點),只有在發(fā)現(xiàn)前繼節(jié)點是頭節(jié)點時,才會通過tryAcquire嘗試獲得鎖,這里有一個比較另我困惑的地方,就是head是一個volatile的全局引用,這么做的話顯然違背了CLH鎖的Local Spin的思想,具體原因未知,可能是因為AQS最初就是被設(shè)計為阻塞的同步器而不是自旋鎖吧。

Condition

Node類的nextWaiter字段其實是用來存放Condition隊列的后繼的,要和next字段(用來存放CLH隊列后繼)進行區(qū)分。

之所以Condition隊列和CLH隊列都采用Node類作為節(jié)點的原因就是為了方便將節(jié)點從Condition隊列搬運到CLH隊列。

圖解java.util.concurrent源碼(一)AbstractQueuedSynchronizer(AQS)

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

相關(guān)閱讀更多精彩內(nèi)容

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