【Java】CLH 自旋锁

2024-05-24 21:48
文章标签 java 自旋 clh

本文主要是介绍【Java】CLH 自旋锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看java重入锁的代码,遇到了CLH队列锁,发现实现很巧妙,学习一下。

什么是自旋锁?说的是锁等待的实现方式,可以改变线程的状态,让其进入等待或者睡眠(具体状态还没研究),这就是使用线程最原生的方式实现。也可以让线程进入一个while循环,这是一种轻量级实现,没有设计线程状态的转换,节省了转换的开销,但是cpu开销可能很大,进入循环的方式就是自旋锁。

下面是一段很常见的理解CLH的代码:

class ClhSpinLock {private final ThreadLocal<Node> prev;private final ThreadLocal<Node> node;private final AtomicReference<Node> tail = new AtomicReference<Node>(new Node());public ClhSpinLock() {this.node = new ThreadLocal<Node>() {protected Node initialValue() {return new Node();}};this.prev = new ThreadLocal<Node>() {protected Node initialValue() {return null;}};}public void lock() {final Node node = this.node.get();node.locked = true;// 一个CAS操作即可将当前线程对应的节点加入到队列中,// 并且同时获得了前继节点的引用,然后就是等待前继释放锁Node pred = this.tail.getAndSet(node);this.prev.set(pred);while (pred.locked) {// 进入自旋}}public void unlock() {final Node node = this.node.get();node.locked = false;this.node.set(this.prev.get());}private static class Node {private volatile boolean locked;}
}
摘自: http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-aqs-clh-and-spin-lock.html

一个锁类有两种共享变量,第一种是线程私有的,即ThreadLocal类型,线程之间不会影响。另一种就是共享的,线程之间可见。

共享的是一个tail指针,指向整个等待队列的最后一个元素。这个也必须是共享的,否则各个线程就没有关系了。通过这个共享变量,把整个队列联系起来。另外两个变量是线程私有的,每一个线程在内部都有副本。myNode指的是当前线程对应的node,pred指的是当前线程的前驱节点。

在lock方法内,首先得到当前线程的myNode节点,这个是通过ThreadLocal的intialize方法实现的,默认返回一个新的节点代表当前线程。设置node的属性locked为true表明在使用锁,其后继节点就会在这个变量上循环。这时当前线程还没有和整个队列建立关系,所以接下来要通过全局的tail变量把自己接入队列。调用tail的getAndSet,得到当前的tail命名为pred,然后把自己设置为tail,那么pred就是当前节点的前驱节点。这个过程是通过CAS控制并发的。这时当前线程已经得到了前驱,而且把自己设置为tail,那么就先用自己的prev变量缓存前驱,在前驱上while循环。只有前驱把自己的locked设置为false,才会停止while。

这样每一个线程都通过这样的方法,用tail形成一个队列,然后在前驱自旋。整个构成是通过ThreadLocal来创建新的节点。


这篇关于【Java】CLH 自旋锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/999621

相关文章

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

Spring Boot读取配置文件的五种方式小结

《SpringBoot读取配置文件的五种方式小结》SpringBoot提供了灵活多样的方式来读取配置文件,这篇文章为大家介绍了5种常见的读取方式,文中的示例代码简洁易懂,大家可以根据自己的需要进... 目录1. 配置文件位置与加载顺序2. 读取配置文件的方式汇总方式一:使用 @Value 注解读取配置方式二

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中的@SneakyThrows注解用法详解

《Java中的@SneakyThrows注解用法详解》:本文主要介绍Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常... 目录前言一、@SneakyThrows 简介1.1 什么是 Lombok?二、@SneakyThrows

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Spring 请求之传递 JSON 数据的操作方法

《Spring请求之传递JSON数据的操作方法》JSON就是一种数据格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,因此JSON本质是字符串,主要负责在不同的语言中数据传递和交换,这... 目录jsON 概念JSON 语法JSON 的语法JSON 的两种结构JSON 字符串和 Java 对象互转

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用