MCS锁 简介

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

概述

上一篇分析了CLH锁,这篇分析一下MCS锁。如果没有看过上一篇的话,建议先看一下 CLH锁简介,本篇是在上一篇的基础上做了简单的描述。

简述

MCS 的名字也是由发明人的名字字幕组合来的(John Mellor-Crummey and Michael Scott)。MCS与CLH最大的不同是,CLH在前驱节点上判断是否获得锁,MCS则是在自身的节点上判断是否能够获取到锁。

Java代码

public class MCSLock {

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

    private AtomicReference tail;
    private ThreadLocal myNode;

    public MCSLock() {
        tail = new AtomicReference(null);
        myNode = new ThreadLocal() {
            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锁的等待队列是一个显示的单向链表。

lock()

lock方法先将自身的locked属性设置为true,将tail节点上的对象的next变量设置为自己,然后在自身的locked变量上等待锁。

unlock()

unlock方法先判断后面有没有对象在等待获取锁,如果有的话将后面对象的locked变量设置为false,即通知后面的对象可以执行任务了,随即将自身的next至空(因为是ThreadLocal类型的变量,用完清理,在上一篇讲解CLH锁的时候有说明),如果后面没有对象在等待的话,将tail节点至空(这里是一个CAS操作),如果CAS至空操作失败,证明后面又有对象申明了锁,下面的 while(null == qnode.next) 循环则是为了确保后面的对象被成功加入到等待队列(链表)的保护工作。

 

 

转载于:https://my.oschina.net/u/232911/blog/3029625

你可能感兴趣的:(MCS锁 简介)