写点什么

「并发原理专题」AQS 的技术体系之 CLH、MCS 锁的原理及实现

作者:Java高工P7
  • 2021 年 11 月 11 日
  • 本文字数:1140 字

    阅读完需:约 4 分钟

public class CLHLock {


private final AtomicReference<Node> tail;


private final ThreadLocal<Node> myNode;


private final ThreadLocal<Node> myPred;


public CLHLock() {


tail = new AtomicReference<>(new Node());


myNode = ThreadLocal.withInitial(() -> new Node());


myPred = ThreadLocal.withInitial(() -> null);


}


public void lock(){


Node node = myNode.get();


node.locked = true;


Node pred = tail.getAndSet(node);


myPred.set(pred);


while (pred.locked){}


}


public void unLock(){


Node node = myNode.get();


node.locked=false;


myNode.set(myPred.get());


}


static class Node {


volatile boolean locked = false;


}


}

MCS 锁

MSC 与 CLH 最大的不同并不是链表是显示还是隐式,而是线程自旋的规则不同:CLH 是在前趋结点的 locked 域上自旋等待,而 MCS 是在自己的结点的 locked 域上自旋等待。正因为如此,它解决了 CLH 在 NUMA 系统架构中获取 locked 域状态内存过远的问题 。

MCS 锁具体实现规则:

  • a. 队列初始化时没有结点,tail=null

  • b. 线程 A 想要获取锁,将自己置于队尾,由于它是第一个结点,它的 locked 域为 false

  • c. 线程 B 和 C 相继加入队列,a->next=b,b->next=c,B 和 C 没有获取锁,处于等待状态,所以 locked 域为 true,尾指针指向线程 C 对应的结点

  • d. 线程 A 释放锁后,顺着它的 next 指针找到了线程 B,并把 B 的 locked 域设置为 false,这一动作会触发线程 B 获取锁。


public class MCSLock {


private final AtomicReference<Node> tail;


private final ThreadLocal<Node> myNode;


public MCSLock() {


tail = new AtomicReference<>();


myNode = ThreadLocal.withInitial(() -> new Node());


}


public void lock() {


Node node = myNode.get();


Node pred = tail.getAndSet(node);


if (pred != null) {


node.locked = true;


pred.next = node;


while (node.locked) {


}


}


}


public void unLock() {


Node node = myNode.get();


if (node.next == null) {


if (tail.compareAndSet(node, null)) {


return;


}


while (node.next == null) {


}


}


node.next.locke


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


d = false;


node.next = null;


}


class Node {


volatile boolean locked = false;


Node next = null;


}


public static void main(String[] args) {


MCSLock lock = new MCSLock();


Runnable task = new Runnable() {


private int a;


@Override


public void run() {


lock.lock();


for (int i = 0; i < 10; i++) {


a++;


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


}


System.out.println(a);


lock.unLock();


}


};


new Thread(task).start();


new Thread(task).start();


new Thread(task).start();


new Thread(task).start();}}

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
「并发原理专题」AQS的技术体系之CLH、MCS锁的原理及实现