并发系列(3)之 CLH、MCS 队列锁简介

并发系列(3)之 CLH、MCS 队列锁简介这篇博客主要是作为AbstractQueuedSynchronizer的背景知识介绍;平时接触也非常的少,如果你不感兴趣可以跳过;但是了解一下能更加的清楚AQS的设计思路;一、自旋锁简介通

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

这篇博客主要是作为 AbstractQueuedSynchronizer 的背景知识介绍;平时接触也非常的少,如果你不感兴趣可以跳过;但是了解一下能更加的清楚 AQS 的设计思路;

一、自旋锁简介

通常情况下解决多线程共享资源逻辑一致性问题有两种方式:

  • 互斥锁:当发现资源被占用的时候,会阻塞自己直到资源解除占用,然后再次尝试获取;
  • 自旋锁:当发现占用时,一直尝试获取锁(线程没有被挂起的过程,也就没有线程调度切换的消耗);

对于这两种方式没有优劣之分,只有是否适合当前的场景;具体的对比就不在继续深入了,如果你很感兴趣可以查看 《多处理器编程的艺术》 提取码:rznn ;

但是如果竞争非常激烈的时候,使用自旋锁就会产生一些额外的问题:

  • 可能导致一些线程始终无法获取锁(争抢的时候必然是当前活跃线程获得锁的几率大),也就是饥饿现象;
  • 因为自旋锁会依赖一个共享的锁标识,所以竞争激烈的时候,锁标识的同步也需要消耗大量的资源;
  • 如果要用自旋锁实现公平锁(即先到先获取),此时就还需要额外的变量,也会比较麻烦;

解决这些问题其中的一种办法就是使用队列锁,简单来讲就是让这些线程排队获取;下面我们介绍常用的两种,即 CLH 锁MCS 锁

二、CLH 锁

CLH 是 Craig、Landin 和 Hagersten 三位作者的缩写,具体内容在 《Building FIFO and Priority-Queuing Spin Locks from Atomic Swap》 论文中有详细介绍,大家可以自行查看;我们 JDK 中 java.util.concurrent.locks.AbstractQueuedSynchronizer 就是根据 CLH 锁的变种实现的;

简单实现:

public class CLH implements Lock {
  private final ThreadLocal<Node> preNode = ThreadLocal.withInitial(() -> null);
  private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new);
  private final AtomicReference<Node> tail = new AtomicReference<>(new Node());

  private static class Node {
    private volatile boolean locked;
  }

  @Override
  public void lock() {
    final Node node = this.node.get();
    node.locked = true;
    Node pre = this.tail.getAndSet(node);
    this.preNode.set(pre);
    while (pre.locked) ;
  }

  @Override
  public void unlock() {
    final Node node = this.node.get();
    node.locked = false;
    this.node.set(this.preNode.get());
  }
}


clh

三、MCS 锁

同样 MCS 是 John M. Mellor-Crummey 和 Michael L. Scott 名字的缩写,具体内容可以在 《Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors》 论文中查看;

简单实现:

public class MCS implements Lock {
  private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new);
  private final AtomicReference<Node> tail = new AtomicReference<>();

  private static class Node {
    private volatile boolean locked = false;
    private volatile Node next = null;
  }

  @Override
  public void lock() {
    Node node = this.node.get();
    node.locked = true;
    Node pre = tail.getAndSet(node);
    if (pre != null) {
      pre.next = node;
      while (node.locked) ;
    }
  }

  @Override
  public void unlock() {
    Node node = this.node.get();
    if (node.next == null) {
      if (tail.compareAndSet(node, null)) {
        return;
      }
      while (node.next == null) ;
    }
    node.next.locked = false;
    node.next = null;
  }
}


clh

总结

  • 以上的代码我已经测试过,大家可以直接拿下来自行实验;
  • CLH 锁和 MCS 锁区别主要有两点:1. 链表结构的区别;2. 自旋对象的区别,CLH 是在前驱节点上自旋,而 MCS 是在自身节点上自旋;这里第二点才是最重要的,主要体现在 SMP(Symmetric Multi-Processor)NUMA(Non-Uniform Memory Access) 不同的处理器架构上;这里大家可以自行 Google;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/167689.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 什么是javabean及其用法

    什么是javabean及其用法一、什么是JavaBean  JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:这个Java类必须具有一个无参的构造函数 属性必须私有化。 私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。javaBean范例:1packagegacl.javabean.study;23/**4…

    2022年7月17日
    12
  • linux中如何给文件重命名_ppt重命名怎么恢复

    linux中如何给文件重命名_ppt重命名怎么恢复Linux下文件重命名、创建、删除、修改及保存文件一、重命名(更名)linux给文件改名的命令是mv命令mv命令来为文件或目录改名或将文件由一个目录移入另一个目录中。该命令等同于DOS系统下的ren和move命令的组合。它的使用权限是所有用户。格式mv[options]源文件或目录目标文件或目录。主要参数[options]-i:交互方式操作。如果mv操作将导致对已存在的目标文…

    2025年8月27日
    6
  • Hibernate初级入门

    Hibernate初级入门

    2021年7月10日
    86
  • ft232芯片怎么样_引脚悬空是什么电平

    ft232芯片怎么样_引脚悬空是什么电平概述:FF4232H芯片一款专门用于USB到RS232/RS485/RS422之间的电平转换芯片,数据收发和协议转换工作全由芯片独立完成,无需人工干预,不用编写芯片的固件,给设计者带来了极大的便利。利用该芯片只需要加少量的外围电路就可以实现相应的转换。FT4232H采用64-LDLeadFreeLQFPorQFN封装工艺。一、FT4232H功能和特性1、单芯片到4路串口的转换,整个接口协…

    2022年8月10日
    5
  • APK反编译之smali[通俗易懂]

    APK反编译之smali[通俗易懂]APK、Dalvik字节码和smali文件大家都应该知道APK文件其实就是一个MIME为ZIP的压缩包,我们修改ZIP后缀名方式可以看到内部的文件结构,例如修改后缀后用RAR打开鳄鱼小顽皮APK能看到的是(GooglePlay下载的完整版版本):   Where’sMyWater.zip\asset\            &lt;资源目录1:asse…

    2022年9月18日
    3
  • 如何修改opkg 源

    如何修改opkg 源http://downloads.openwrt.org.cn/上面的链接是openwrt国内的源,但是只有适合以下几个系统的源Hacked/18-Jun-201413:58-OpenWrt-DreamBox/01-J

    2022年5月9日
    207

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号