自旋锁与CLH锁

AQS 类的核心数据结构是一种名为 Craig, Landin, and Hagersten locks(下称 CLH 锁)的变体。

在并发编程中,锁是一种常用的保证线程安全的方法。

Java 中常用的锁主要有两类,一种是关键字 _index ,被称为 Java 内置锁或监视器锁。

另一种就是在 J2SE 1.5版本之后的 java.util.concurrent包(下称j.u.c包)中的各类同步器

包括 ReentrantLock(可重入锁),ReentrantReadWriteLock(可重入读写锁),Semaphore(信号量),CountDownLatch 等

这些同步器都是基于 AbstractQueuedSynchronizer(下称 AQS)这个简单的框架来构建的

AQS 类的核心数据结构是一种名为 Craig, Landin, and Hagersten locks(下称 CLH 锁)的变体。

CLH锁是自旋锁的一种改良

自旋锁

自旋锁是互斥锁的一种实现, 用于保证线程间正确互斥

获取锁时,线程会对一个原子变量循环执行 compareAndSet 方法,直到该方法返回成功时即为成功获取锁

compareAndSet 方法底层由[[atomic]]实现

![[content/en/java/Basic/Concurrent/Pasted image 20250203201648.png]]

自旋锁减少了线程上下文开销, 减缓了频繁的线程挂起操作

但是该锁有很严重的缺点

  • 饥饿问题, 竞争激烈下, 可能有线程一直得不到锁
  • 性能问题, 长时间自旋并且由于锁状态变更需要修改状态变量, 导致CPU的高速缓存在线程间频繁同步, 很消耗CPU ![[content/en/java/Basic/Concurrent/Pasted image 20250203202833.png]]

CLH锁

volatile关键字

这是对自旋锁的改进版本 主要针对上述两个缺点做了改进

  • 饥饿问题, 将线程组织为队列, 先来先服务, 防止饥饿问题
  • 去中心化, 不在使用单独的锁状态变量, 而是在每个线程内维护一个状态变量, 后继线程监视前继线程的状态即可 CLH 锁数据结构很简单,类似一个链表队列,所有请求获取锁的线程会排列在链表队列中,自旋访问队列中前一个节点的状态。

![[content/en/java/Basic/Concurrent/Pasted image 20250203203420.png]]

  1. CLH 锁初始化时会 Tail 会指向一个状态为 false 的空节点,如图1所示。

  2. 当 Thread 1(下称 T1)请求获取锁时,Tail 节点指向 T1 对应的节点,同时返回空节点。T1 检查到上一个节点状态为 false,就成功获取到锁,可以执行相应的逻辑了,如图2所示。

  3. 当 Thread 2(下称 T2)请求获取锁时,Tail 节点指向 T2 对应的节点,同时返回 T1 对应的节点。T2检查到上一个节点状态为 True,无法获取到锁,于是开始轮询上一个节点的状态,如图3所示。

  4. 当 T1 释放锁时,会将状态变量置为 False,如图4所示。

  5. T2 轮询到检查到上一个节点状态变为 False,则获取锁成功,如图5所示。

Java 源码

![[content/en/java/Basic/Concurrent/Pasted image 20250203203732.png]]

了解 ThreadLocal

利用 ThreadLocal 在独立线程内存维护node, node中只存储了该线程锁状态

  • 为什么锁要加 volatile 注意, 虽然锁状态只由宿主线程读取写入, 是单线程操作没必要保证可见性, 但是作为互斥锁需要保证 happen-before 规则成立, 这就意味着一个监视器锁的解锁发生在该监视器锁的后续锁定之前, 因此为了防止无法预测的重排序导致锁的状态在读取完成前被修改, 使用[[volatile关键字]]禁止重排序

  • 为什么作为链表, node中不存储后继指针 很简单, 因为不需要, 作为先来先服务的队列, 没必要在乎后续节点的状态 只要前一个节点释放锁, 就立刻获取即可

CLH 锁作为自旋锁的改进,有以下几个优点:

  1. 性能优异,获取和释放锁开销小。释放锁的开销因为不需要使用 CAS 指令而降低了。

  2. 公平锁。先入队的线程会先得到锁。

  3. 实现简单,易于理解。

当然,它也有两个缺点:第一是因为有自旋操作,当锁持有时间长时会带来较大的 CPU 开销。第二是基本的 CLH 锁功能单一,不改造不能支持复杂的功能。

[!引用] Quner技术沙龙 https://mp.weixin.qq.com/s/jEx-4XhNGOFdCo4Nou5tqg