我理解的CLH



學而時習之,不亦說乎!

                             --《論語》

原創,轉載請附原文鏈接,謝謝。

CLH

思路

  • 保持時序的鎖基本思路就是將等待獲取鎖的線程放入集合,鎖釋放后,等待線程之一獲取到鎖。

問題

  • 如何排隊?

    • CLH使用反向鏈表的形式進行排隊。也就是后繼節點主動詢問,而不是前繼節點主動通知。
  • 排隊是否公平?

    • CLH是公平鎖。即后申請獲取鎖的排在隊列末尾。
  • 如何喚醒?

    • CLH通過每個線程自旋。每個等待線程通過不斷自旋前繼節點狀態判斷是否能獲取到鎖。

實現

  • CLH排隊使用公平方式,鎖內部需要保存【尾節點】的引用,每次排隊線程加入到隊列最末尾。
  • CLH鎖使用反向鏈表方式進行排隊,那么每個線程就需要維護【自己的狀態】和保持一個【前向節點的引用】。
  • CLH使用一個【boolean值】表示當前線程獲取鎖狀態。false表示當前線程釋放鎖;true表示當前線程等待獲取鎖或已經獲取到鎖。

代碼

Lock.java

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
public interface Lock {
    void lock();
    void unlock();
}
 

CLHLock.java

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
import java.util.concurrent.atomic.AtomicReference;
public class CLHLock implements Lock {
    private final AtomicReference<QNode> tail;
    private final ThreadLocal<QNode> myPred;
    private final ThreadLocal<QNode> myNode;
    public CLHLock() {
        tail = new AtomicReference<QNode>(new QNode());
        myNode = new ThreadLocal<QNode>() {
            @Override
            protected QNode initialValue() {
                return new QNode();
            }
        };
        myPred = new ThreadLocal<QNode>() {
            @Override
            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());這一行是否有必要???
    }
    private static class QNode {
        public volatile boolean locked;
    }
}
 

測試

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CLHMain {
    private Lock lock = new CLHLock();
    public void say(String msg) {
        System.out.println(Thread.currentThread().getName() + " : 嘗試獲取鎖");
        lock.lock();
        System.out.println(Thread.currentThread().getName() + " : 獲取到鎖");
        try {
            System.out.println(Thread.currentThread().getName() + msg + "?");
            TimeUnit.SECONDS.sleep(1);
            System.out.println(Thread.currentThread().getName() + msg + "!");
            TimeUnit.SECONDS.sleep(1);
            System.out.println(Thread.currentThread().getName() + msg + ".");
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName() + " : 釋放鎖");
        }
    }
    public static void main(String[] args) throws Exception {
        String msg = "Hello,World";
        CLHMain clhMain = new CLHMain();
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    clhMain.say(msg);
                }
            });
        }
        executorService.awaitTermination(20, TimeUnit.SECONDS);
    }
}
 

結果

 
 
 
xxxxxxxxxx
 
 
 
 
pool-1-thread-1 : 嘗試獲取鎖
pool-1-thread-2 : 嘗試獲取鎖
pool-1-thread-1 : 獲取到鎖
pool-1-thread-1Hello,World?
pool-1-thread-3 : 嘗試獲取鎖
pool-1-thread-4 : 嘗試獲取鎖
pool-1-thread-5 : 嘗試獲取鎖
pool-1-thread-1Hello,World!
pool-1-thread-1Hello,World.
pool-1-thread-1 : 釋放鎖
pool-1-thread-2 : 獲取到鎖
pool-1-thread-2Hello,World?
pool-1-thread-2Hello,World!
pool-1-thread-2Hello,World.
pool-1-thread-2 : 釋放鎖
pool-1-thread-3 : 獲取到鎖
pool-1-thread-3Hello,World?
pool-1-thread-3Hello,World!
pool-1-thread-3Hello,World.
pool-1-thread-3 : 釋放鎖
pool-1-thread-4 : 獲取到鎖
pool-1-thread-4Hello,World?
pool-1-thread-4Hello,World!
pool-1-thread-4Hello,World.
pool-1-thread-4 : 釋放鎖
pool-1-thread-5 : 獲取到鎖
pool-1-thread-5Hello,World?
pool-1-thread-5Hello,World!
pool-1-thread-5Hello,World.
pool-1-thread-5 : 釋放鎖
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM