http://blog.csdn.net/aesop_wubo/article/details/7533186
CLH鎖即Craig, Landin, and Hagersten (CLH) locks。CLH鎖是一個自旋鎖。能確保無飢餓性。提供先來先服務的公平性。
CLH鎖也是一種基於鏈表的可擴展、高性能、公平的自旋鎖,申請線程僅僅在本地變量上自旋,它不斷輪詢前驅的狀態,假設發現前驅釋放了鎖就結束自旋。
SMP(Symmetric Multi-Processor)。即對稱多處理器結構,指server中多個CPU對稱工作,每一個CPU訪問內存地址所需時間同樣。其主要特征是共享,包括對CPU,內存,I/O等進行共享。SMP的長處是可以保證內存一致性。缺點是這些共享的資源非常可能成為性能瓶頸。隨着CPU數量的添加,每一個CPU都要訪問同樣的內存資源,可能導致內存訪問沖突,可能會導致CPU資源的浪費。經常使用的PC機就屬於這樣的。
NUMA(Non-Uniform Memory Access)非一致存儲訪問,
將CPU分為CPU模塊,每一個CPU模塊由多個CPU組成,
而且具有獨立的本地內存、
I/O
槽口等,模塊之間能夠通過互聯模塊
相互訪問
,訪問本地內存的速度將遠遠高於訪問遠地內存
(
系統內其他節點的內存
)
的速度,這也是非一致存儲訪問
NUMA
的由來。
NUMA長處是
能夠較好地解決原來
SMP
系統的擴展問題,缺點是因為
訪問遠地內存的延時遠遠超過本地內存,因此當
CPU
數量添加時。系統性能無法線性添加。
CLH算法實現
CLH隊列中的結點QNode中含有一個locked字段,該字段若為true表示該線程須要獲取鎖,且不釋放鎖。為false表示線程釋放了鎖。
結點之間是通過隱形的鏈表相連,之所以叫隱形的鏈表是由於這些結點之間沒有明顯的next指針,而是通過myPred所指向的結點的變化情況來影響myNode的行為。
CLHLock上另一個尾指針,始終指向隊列的最后一個結點。
CLHLock的類圖例如以下所看到的:

當一個線程須要獲取鎖時,會創建一個新的QNode。將當中的locked設置為true表示須要獲取鎖。然后線程對tail域調用getAndSet方法,使自己成為隊列的尾部。同一時候獲取一個指向其前趨的引用myPred,然后該線程就在前趨結點的locked字段上旋轉。直到前趨結點釋放鎖。
當一個線程須要釋放鎖時,將當前結點的locked域設置為false。同一時候回收前趨結點。例如以下圖所看到的,線程A須要獲取鎖。其myNode域為true。些時tail指向線程A的結點,然后線程B也增加到線程A后面。tail指向線程B的結點。然后線程A和B都在它的myPred域上旋轉,一量它的myPred結點的locked字段變為false,它就能夠獲取鎖掃行。明顯線程A的myPred locked域為false,此時線程A獲取到了鎖。

整個CLH的代碼例如以下,當中用到了ThreadLocal類,將QNode綁定到每個線程上,同一時候用到了AtomicReference,對尾指針的改動正是調用它的getAndSet()操作來實現的,它可以保證以原子方式更新對象引用。
- public class CLHLock implements Lock {
- AtomicReference<QNode> tail = new AtomicReference<QNode>(new QNode());
- ThreadLocal<QNode> myPred;
- ThreadLocal<QNode> myNode;
- public CLHLock() {
- tail = new AtomicReference<QNode>(new QNode());
- myNode = new ThreadLocal<QNode>() {
- protected QNode initialValue() {
- return new QNode();
- }
- };
- myPred = new ThreadLocal<QNode>() {
- protected QNode initialValue() {
- return null;
- }
- };
- }
- @Override
- public void lock() {
- QNode qnode = myNode.get();
- qnode.locked = true;
- QNode pred = tail.getAndSet(qnode);
- myPred.set(pred);
- while (pred.locked) {
- }
- }
- @Override
- public void unlock() {
- QNode qnode = myNode.get();
- qnode.locked = false;
- myNode.set(myPred.get());
- }
- }
CLH優缺點
CLH隊列鎖的長處是空間復雜度低(
假設有n個線程。L個鎖,每一個線程每次僅僅獲取一個鎖,那么須要的存儲空間是O(L+n),n個線程有n個myNode。L個鎖有L個tail),CLH的一種變體被應用在了JAVA並發框架中。唯一的缺點是在NUMA系統結構下性能非常差。在這樣的系統結構下,每一個線程有自己的內存,假設前趨結點的內存位置比較遠。自旋推斷前趨結點的locked域,性能將大打折扣,可是在SMP系統結構下該法還是非常有效的。
一種解決NUMA系統結構的思路是MCS隊列鎖。
參考資料:
The Art of Multiprocessor Programming