一、

1、SMP(Symmetric Multi-Processor)

SMP(Symmetric Multi-Processing)对称多处理器结构,指服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。

SMP能够保证内存一致性,但这些共享的资源很可能成为性能瓶颈,随着CPU数量的增加,每个CPU都要访问相同的内存资源,可能导致内存访问冲突,

可能会导致CPU资源的浪费。常用的PC机就属于这种。

2、NUMA(Non-Uniform Memory Access)

非一致存储访问,将CPU分为CPU模块,每个CPU模块由多个CPU组成,并且具有独立的本地内存、I/O槽口等,模块之间可以通过互联模块相互访问,访问本地内存的速度将远远高于访问远地内存(系统内其它节点的内存)的速度,这也是非一致存储访问的由来。NUMA较好地解决SMP的扩展问题,

当CPU数量增加时,因为访问远地内存的延时远远超过本地内存,系统性能无法线性增加。

二、

1、CLH锁

CLH(Craig, Landin, and Hagersten  locks): 是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。

CLH锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。

当一个线程需要获取锁时:

a.创建一个的QNode,将其中的locked设置为true表示需要获取锁

b.线程对tail域调用getAndSet方法,使自己成为队列的尾部,同时获取一个指向其前趋结点的引用myPred

c.该线程就在前趋结点的locked字段上旋转,直到前趋结点释放锁

d.当一个线程需要释放锁时,将当前结点的locked域设置为false,同时回收前趋结点

  如下图,线程A需要获取锁,其myNode域为true,tail指向线程A的结点,然后线程B也加入到线程A后面,tail指向线程B的结点。然后线程A和B都在其myPred域上旋转,一旦它的myPred结点的locked字段变为false,它就可以获取锁。明显线程A的myPred locked域为false,此时线程A获取到了锁。

2、CLH代码示例

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());  }
}

3、CLH分析

CLH队列锁的优点是空间复杂度低(如果有n个线程,L个锁,每个线程每次只获取一个锁,那么需要的存储空间是O(L+n),n个线程有n个。myNode,L个锁有L个tail),CLH的一种变体被应用在了JAVA并发框架中。

CLH在SMP系统结构下该法是非常有效的。但在NUMA系统结构下,每个线程有自己的内存,如果前趋结点的内存位置比较远,自旋判断前趋结点的locked域,性能将大打折扣,一种解决NUMA系统结构的思路是MCS队列锁。

三、

1、MCS锁

MSC与CLH最大的不同并不是链表是显示还是隐式,而是线程自旋的规则不同:CLH是在前趋结点的locked域上自旋等待,而MSC是在自己的结点的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获取锁

2、代码实现

public class MCSLock implements Lock {AtomicReference<QNode> tail;ThreadLocal<QNode> myNode;@Overridepublic void lock() {QNode qnode = myNode.get();QNode pred = tail.getAndSet(qnode);if (pred != null) {qnode.locked = true;pred.next = qnode;// wait until predecessor gives up the lockwhile (qnode.locked) {}}}@Overridepublic void unlock() {QNode qnode = myNode.get();if (qnode.next == null) {if (tail.compareAndSet(qnode, null))return;// wait until predecessor fills in its next fieldwhile (qnode.next == null) {}}qnode.next.locked = false;qnode.next = null;}class QNode {boolean locked = false;QNode next = null;}
}

转载于:https://www.cnblogs.com/llkmst/p/4895478.html

CLH锁 、MCS锁相关推荐

  1. CLH、MCS锁的原理及实现

    一.背景 1.1 SMP(Symmetric Multi-Processor) 对称多处理器结构,它是相对非对称多处理技术而言的.应用十分广泛的并行技术.在这种架构中,一台计算机由多个CPU组成,并共 ...

  2. php 自旋锁,自旋锁、排队自旋锁、MCS锁、CLH锁(转)

    自旋锁(Spin lock) 转:http://coderbee.net/index.php/concurrent/20131115/577 自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程 ...

  3. 水货笨叔介绍MCS锁

    前几天小明同学和笨叔抱怨:现在的spinlock锁的代码变得越来越复杂了,我都看不懂了.的确spinlock的代码从原来简单的几行代码,变成现在复杂的几百行,除了代码变得复杂,里面隐含的原理也不简单. ...

  4. 吃透Java并发:AQS结构详解及其CLH变种、CLH、MCS

    目录 1.前言 2.AQS的构成 2.1 状态信息state 2.2 节点信息Node 2.3 阻塞/唤醒 2.4 当前持有锁线程 2.5 头结点与尾节点 3.CLH队列 3.1 CLH锁 3.2 M ...

  5. 理解悲观锁乐观锁、同步锁、读锁、写锁

    ava 锁分类 Java 中的锁有很多,可以按照不同的功能.种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 从线程是否需要对资源加锁可以分为 悲观锁 和 乐观锁 从资源已被 ...

  6. JUC锁-互斥锁ReentrantLock(二)

    ReentrantLock介绍 ReentrantLock是一个可重入的互斥锁,又被称为"独占锁". 顾名思义,ReentrantLock锁在同一个时间点只能被一个线程锁持有:而可 ...

  7. [精选]MySQL的各种锁(表锁,行锁,悲观锁,乐观锁,间隙锁,死锁)

    不少人在开发的时候,应该很少会注意到这些锁的问题,也很少会给程序加锁(除了库存这些对数量准确性要求极高的情况下),即使我们不会这些锁知识,我们的程序在一般情况下还是可以跑得好好的.因为数据库隐式帮我们 ...

  8. jvm第7节-锁(偏向锁,轻量锁,自旋锁)

    为什么80%的码农都做不了架构师?>>>    在介绍锁之前我们先介绍一个线程不安全的例子,一个全局的list,开2个线程往里面插入数据,代码如下: package com.jvm. ...

  9. 《Redis官方文档》用Redis构建分布式锁(悲观锁)

    2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...

最新文章

  1. html画三个重叠的矩形,html5 实现两个矩形的叠加
  2. Python简介及安装
  3. 全球及中国水软化盐行业消费规模及市场现状调研分析报告2022-2027年
  4. 使用vue的transition完成滑动过渡
  5. 阅读书源最新2020在线导入_书源篇三及6.5.0版本介绍
  6. linux下如何使用configure/make/make install命令编译安装卸载程序
  7. 网上科学计算机,【图片】计算机-科普—都是从网上找的【计算机科学与技术吧】_百度贴吧...
  8. 关于双向反射率BRDF的定义
  9. Python之定义默认参数
  10. 「代码随想录」337.打家劫舍III 【动态规划】力扣详解!
  11. Control-Tree
  12. 统计学习基础(第二版)——引言
  13. python名词_使用Python词性标记提取名词(循环)
  14. Android ContextThemeWrapper cannot be cast to android.app.Activity
  15. iOS placeholder换行
  16. Pytorch阅读文档之flatten函数
  17. 程序员的最高境界(转)
  18. mysql行锁/表锁
  19. H5兄弟连web前端
  20. python扇贝单词书,成功使用Python爬虫扇贝单词库实现自动测试我们的单词量

热门文章

  1. ***检测与防护(IDS/IPS)
  2. centos配置-java-php-mysql【转载参考】
  3. 图解完整模式安装windows server 2008企业版[为企业部署Windows Server 2008系列四]
  4. python公共键_Python利用公共键如何对字典列表进行排序详解
  5. pycharm 常用快捷键整理
  6. FPGA异步时序和多时钟模块
  7. Web系统中Mic设备的应用实例
  8. ROS_机器人urdf建模仿真实践
  9. XML文档操作工具类
  10. 文件压缩和文件打包命令