面試題上看到CLH鎖的實現原理,想找視頻看看沒找到,各種博客寫的也很抽象,缺乏形象感不易理解。於是就自己寫一個,爭取做到通俗易懂。
CLH鎖是自旋鎖的一種實現方式 (java自旋鎖的4種實現方式),實現了自旋鎖的公平性,即按照請求鎖的時間先後順序來獲取鎖。之所以叫CLH鎖, 是因爲它的作者是Craig,Landin andHagersten,取他們的名字首字母而命名的。
CLHLock可以創建節點QNode, QNode中有一個boolean變量locked,它的作用是表示自己是否有“需求”。
CLHLock有兩個ThreadLocal變量,myNode 用來指向當前節點,myPred用來指向當前節點的前驅節點;
還有一個AtomicReference變量tail用來標示List的尾部位置,大家排隊的話都自覺從尾部往後排。
下面線程們都來獲取鎖啦!
(1)
首先來的是Thread1,它上來要先創建一個QNode,並且把locked置爲 true,大聲宣佈自己對鎖有需求,在自己完成想幹的事之前,是不會把locked置爲false的。
然後它就去找tail ,並且把tail 的標誌拿在自己手裏,表示自己是隊列的尾部,誰要是對鎖也有需求,通通到我身後排隊去。 “喲,我前面沒人!沒事,就當有人!” 只要把myPred 向前指就行了!(myPred=NULL)因爲thread1前面沒有人,所以thread1就拿到鎖了,如下圖
然後thread1佔着鎖,開始忙自己的事。
(2)
這時, thread2來了,表示自己對鎖也有需求,locked置爲true,然後就找 tail 的位置,在後面排隊。thread2一看,thread1已經佔着鎖了,於是他就一直盯着 thread1 的QNode狀態 locked 自旋,
while(thread1. locked == true){}
然後將自己的前一個節點myPred 指向 thread1的 myNode,就等着 thread1 的locked變成 false好去拿鎖。
因爲thread2 排在了 thread1 之後,所以現在thread2纔是隊伍的末尾,所以 tail 氣球就傳到了 thread2手裏,後面再來排隊就要排到thread2後面了。 如下圖:
(3)
這時thread1忙完了,需求解決了,於是他將 locked 置爲 flase,一直盯着thread1的locked標誌自旋的thread2就拿到了鎖。 thread1 將自己的QNode銷燬, 於是thread2的myPred就指向了null, 與之前thread1的處境是一樣一樣的! 後面再有thread3到thread2後面排隊,跟之前的過程也是一樣一樣的!如下圖
這樣,就實現了先到先得的公平CAS。代碼實現看文中鏈接, 理解了原理再去看代碼應該很容易了。