MCS鎖 簡介

概述

上一篇分析了CLH鎖,這篇分析一下MCS鎖。若是沒有看過上一篇的話,建議先看一下 CLH鎖簡介,本篇是在上一篇的基礎上作了簡單的描述。java

簡述

MCS 的名字也是由發明人的名字字幕組合來的(John Mellor-Crummey and Michael Scott)。MCS與CLH最大的不一樣是,CLH在前驅節點上判斷是否得到鎖,MCS則是在自身的節點上判斷是否可以獲取到鎖。node

Java代碼

public class MCSLock {

    public class QNode {
        volatile boolean locked = false;
        QNode next = null;
    }

    private AtomicReference<QNode> tail;
    private ThreadLocal<QNode> myNode;

    public MCSLock() {
        tail = new AtomicReference<QNode>(null);
        myNode = new ThreadLocal<QNode>() {
            protected QNode initialValue() {
                return new QNode();
            }
        };
    }

    public void lock() {
        QNode qnode = myNode.get();
        QNode pred = tail.getAndSet(qnode);
        if (null != pred) {
            qnode.locked = true;
            pred.next = qnode;
        }
        while (qnode.locked) {
        }
    }

    public void unlock() {
        QNode qnode = myNode.get();
        if (null == qnode.next) {
            if (tail.compareAndSet(qnode, null)) {
                return;
            }
            while (null == qnode.next) {
            }
        }
        qnode.next.locked = false;
        qnode.next = null;
    }
}

窺探原理

MCS一樣有一個tail節點,也是存放最後一次申請鎖的對象,另外它只有一個myNode屬性。它的QNode對象內部除了維護一個boolean類型的locked變量,還有一個QNode類型的next變量,用來指向下一個節點。CLH鎖等待隊列是一個邏輯上的隊列,而MCS鎖的等待隊列是一個顯示的單向鏈表。spa

lock()

lock方法先將自身的locked屬性設置爲true,將tail節點上的對象的next變量設置爲本身,而後在自身的locked變量上等待鎖。.net

unlock()

unlock方法先判斷後面有沒有對象在等待獲取鎖,若是有的話將後面對象的locked變量設置爲false,即通知後面的對象能夠執行任務了,隨即將自身的next至空(由於是ThreadLocal類型的變量,用完清理,在上一篇講解CLH鎖的時候有說明),若是後面沒有對象在等待的話,將tail節點至空(這裏是一個CAS操做),若是CAS至空操做失敗,證實後面又有對象申明瞭鎖,下面的 while(null == qnode.next) 循環則是爲了確保後面的對象被成功加入到等待隊列(鏈表)的保護工做。code

相關文章
相關標籤/搜索