当前位置: 首页 > news >正文

自旋锁与CAS

上文我们认识了许许多多的锁,此篇我们的CAS就是从上文的锁策略开展的新概念,我们来一探究竟吧

1. 什么是CAS?

CAS: 全称Compare and swap,字⾯意思:“比较并交换”,⼀个CAS涉及到以下操作:
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。

  1. 比较A与V是否相等。(比较)
  2. 如果比较相等,将B写入V。(交换)
  3. 返回操作是否成功。

CAS伪代码
下面写的代码不是原子的,真实的CAS是⼀个原子的硬件指令完成的.这个伪代码只是辅助理解CAS的工作流程.

while{boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue) {&address = swapValue;return true;}return false;}
}

说明:

  1. address: 表示要修改的内存地址
  2. expectValue: 预期值
  3. swapValue:要设置的新值

执行流程:

  1. 用一个预期值去和内存中的值做比较
  2. 如果预期值与内存中的值相等,就用新的值更新内存中的值
  3. 如果预期值与内存中的值不相等,就用进入下一次比较

我们前面学习过的线程安全问题是由于CPU的随机调度导致的,我们的处理方法是给有关修改共享变量的代码块加了synchronize关键字,保证了原子性,解决了线程安全问题,
那么问题来了,
为什么我们看到的CAS伪代码并没有保证原子性,那么他是如何保证原子性的呢??

我们从一段例子来讲解:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:

  1. CAS对应的是硬件指令cmpxchg从CPU做了原子性支持,与LOCK 、UNLOCK 指令同地位
  2. CAS操作每次读取(LOAD)数据是从主内存中读取,并没有对应的工作内存
  3. 自旋锁是通过while把CAS进行包裹,让CAS没有成功的时候不停的执行,直到成功执行为止
  4. CAS是一个真正的指令,JVM调用了本地方法之后,对应的CAS指令会在CPU上执行
    执行中LOAD数据会访问主内存

2. CAS实现自旋锁

基于CAS实现更灵活的锁,获取到更多的控制权.
自旋锁伪代码:

public class SpinLock {private Thread owner = null;public void lock(){// 通过CAS 看当前锁是否被某个线程持有.  
// 如果这个锁已经被别的线程持有, 那么就⾃旋等待.  
// 如果这个锁没有被别的线程持有, 那么就把owner 设为当前尝试加锁的线程.  
}}while(!CAS(this.owner, null, Thread.currentThread())){}public void unlock (){this.owner = null;}

3. JDK中基于CAS实现的原子类

说明:

  1. JDK中提供了CAS实现的原子类,我们举其中一种AtomicInteger类来说明
    在这里插入图片描述
  2. 我们调用其中的方法getAndIncrement()
//自增 ++i
atomicInteger.getAndIncrement();
  1. 我们发现getAndIncrement()方法本质是getAndIncrement()
public final int getAndIncrement() {return U.getAndAddInt(this, VALUE, 1);
}
  1. 其中调用了Unsafe这个类的方法,是JDK内部的工具类,不建议外部程序员直接调用
private static final Unsafe U = Unsafe.getUnsafe();
//获取内存中字段在对象中的偏移地址private static final long VALUE= U.objectFieldOffset(AtomicInteger.class, "value");
//1. o表示原子类对象
//2. offset表示内存中字段在对象中的偏移地址
//3. delta表示传入的值
public final int getAndAddInt(Object o, long offset, int delta) {int v;do {//v是CAS操作之前获取的预期值v = getIntVolatile(o, offset);} while (!weakCompareAndSetInt(o, offset, v, v + delta));//while不停的自旋return v;}
   public final boolean weakCompareAndSetInt(Object o, long offset,//内存地址int expected,//预期值int x) {//要设置的值return compareAndSetInt(o, offset, expected, x);//最后调用compareAndSetInt()方法}
//native表示本地方法,即对应了一条CAS指令cmpxchg
public final native boolean compareAndSetInt(Object o, long offset,int expected,int x);
  1. 图解如下:
    在这里插入图片描述

4. CAS的ABA问题

首先我们要知道什么是ABA问题???

ABA的问题:
假设存在两个线程t1和t2.有一个共享变量value,初始值为A.
接下来,线程t1想使用CAS把value值改成Z,那么就需要
先读取value的值,记录到oldValue变量中.
使用CAS判定当前value的值是否为A,如果为A,就修改成Z.
但是,在t1执行这两个操作之间,t2线程可能把value的值从A改成了B,又从B改成了A

举个例子: 今天是疯狂星期四,我和我的女友共用一个小荷包吃饭,我和她说如果小荷包里面有100元 (A状态) 晚上6点就点KFC吃,我怕她忘记了,我就先自己点了,此时,小荷包余额为50元 (B状态) 然后我的朋友疯狂星期四V我50,小荷包的钱又变回了100 (A状态),她再点的时候,发现小荷包还是100元,她就再点了一份,就导致多点了一份KFC

那么我们该如何解决ABA问题呢??
在点KFC的例子当中,我们可以让他查看一下消费记录(版本号),此时的100元是否是开始的100元,
由此可得,我们可以可以给value数据加上一个版本号,当线程2要修改时,不仅要value要符合预期值,同时版本号也要符合
即:
CAS操作在读取旧值的同时,也要读取版本号.
真正修改的时候,

  • 如果当前版本号和读到的版本号相同,则修改数据,并把版本号+1.
  • 如果当前版本号高于读到的版本号.就操作失败(认为数据已经被修改过了).

版本号可以用自增的数值,也可以用随机的UUID,也可以使用时间戳

System.out.println(UUID.randomUUID());

生成随机数:
在这里插入图片描述

相关文章:

自旋锁与CAS

上文我们认识了许许多多的锁,此篇我们的CAS就是从上文的锁策略开展的新概念,我们来一探究竟吧 1. 什么是CAS? CAS: 全称Compare and swap,字⾯意思:“比较并交换”,⼀个CAS涉及到以下操作: 我们假设内存中…...

数组-二分查找

目录 算法思想: 实践: 备注: 二分查找是一种高效的查找算法,适用于在 有序数组 或列表中快速定位目标元素的索引。 重要事情说三遍:使用前提:数组有序,无重复,如果数组未排序&am…...

如何使用 Python 进行文件读写操作?

大家好,我是 V 哥。今天的内容来介绍 Python 中进行文件读写操作的方法,这在学习 Python 时是必不可少的技术点,希望可以帮助到正在学习 python的小伙伴。 以下是 Python 中进行文件读写操作的基本方法: 一、文件读取&#xff1…...

springcloud中的Feign调用

目录 一、基础应用 1.feign使用 1.增加feign依赖 2.编写feign接口 3.启用feign 4.调试 5.可能出现的异常信息 1.404 可能原因: 2.503 可有原因: 2.feign自定义配置 1.创建Feign配置类 2.feign接口 3.调试结果 3.feign多参数请求 Feign是Netflix开发的声明…...

【部署】将项目部署到云服务器

目录 1.获得服务器 2.连接到云服务器 3.配置环境 3.1.Java(运行后端所需) 3.2.MySQL数据库 3.3.Nginx(运行前端所需) 3.4. Node.js(构建前端所需) 4.打包项目 4.1.打包后端项目 4.2.打包前端项目…...

2024年AI大模型技术年度总结与应用实战:创新与突破并进

前言 回顾2024年,我一共发布了286篇博文,粉丝数也达到了43000多。这一年里,我收获颇丰,始终坚持AI大模型的研究方向,并且积极开展大模型的实战应用,也取得了一系列令人振奋的突破。 在286篇博文中&#…...

docker离线安装及部署各类中间件(x86系统架构)

前言:此文主要针对需要在x86内网服务器搭建系统的情况 一、docker离线安装 1、下载docker镜像 https://download.docker.com/linux/static/stable/x86_64/ 版本:docker-23.0.6.tgz 2、将docker-23.0.6.tgz 文件上传到服务器上面,这里放在…...

SuperdEye:一款基于纯Go实现的间接系统调用执行工具

关于SuperdEye SuperdEye是一款基于纯Go实现的间接系统调用执行工具,该工具是TartarusGate 的修订版,可以利用Go来实现TartarusGate 方法进行间接系统调用。 该工具的目标是为了扫描挂钩的NTDLL并检索Syscall编号,然后使用它来执行间接系统调…...

PCL 新增自定义点类型【2025最新版】

目录 一、自定义点类型1、前言2、定义方法3、代码示例二、合并现有类型三、点云按时间渲染1、CloudCompare渲染2、PCL渲染博客长期更新,本文最近更新时间为:2025年1月18日。 一、自定义点类型 1、前言 PCL库自身定义了很多点云类型,但是在使用的时候时如果要使用自己定义的…...

Docker导入镜像

使用命令行进行处理&#xff1a; docker load < onething1_wxedge.tar如下图所示 查看状态 docker images...

PyTorch使用教程(9)-使用profiler进行模型性能分析

1、简介 PyTorch Profiler是一个内置的性能分析工具&#xff0c;可以帮助开发者定位计算资源&#xff08;如CPU、GPU&#xff09;的瓶颈&#xff0c;从而更好地优化PyTorch程序。通过捕获和分析GPU的计算、内存和带宽利用情况&#xff0c;能够有效识别并解决性能瓶颈。 2、原…...

SpringBoot中使用MyBatis-Plus详细介绍

目录 一、MyBatis-Plus的使用步骤 1.引入MybatisPlus的起步依赖 2.定义Mapper&#xff08;也叫dao&#xff09;层的接口 3.MyBatis-Plus中常用注解 4. 使用MyBatis-Plus时要做如下配置 5.条件构造器 Wrapper 一、MyBatis-Plus的使用步骤 1.引入MybatisPlus的起步依赖 M…...

PCL 部分点云视点问题【2025最新版】

目录 一、问题概述二、解决方案1、软件实现2、代码实现三、调整之后博客长期更新,本文最近更新时间为:2025年1月18日。 一、问题概述 针对CloudCompare软件处理过的pcd格式点云,在使用PCL进行特征点提取、配准等实验中最终显示结果出现点云位置偏差较大的问题,本博客给出解…...

【Linux】常见指令(三)

Linux常见指令 01.nano02.cat03.cp04.mv 我的Linux专栏&#xff1a;【Linux】 本节Linux指令讲解的基本框架如下&#xff1a; 大家可以根据自己的需求&#xff0c;自行进行跳转和学习&#xff01; 01.nano nano Linux 系统中一款简单易用的命令行文本编辑器&#xff0c;适合…...

第5章:Python TDD定义Dollar对象相等性

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

nuxt3项目打包部署到服务器后配置端口号和开启https

nuxt3打包后的项目部署相对于一般vite打包的静态文件部署要稍微麻烦一些&#xff0c;还有一个主要的问题是开发环境配置的.env环境变量在打包后部署时获取不到&#xff0c;具体的解决方案可以参考我之前文章 nuxt3项目打包后获取.env设置的环境变量无效的解决办法。 这里使用的…...

MongoDB文档查询

一、实验目的 1. 理解MongoDB文档数据库的基本概念和特性。 2. 掌握在MongoDB中创建集合和插入文档数据的方法。 3. 学习使用MongoDB进行文档查询操作&#xff0c;包括查询、过滤和排序等。 二、实验环境准备 1. JAVA环境准备&#xff1a;确保Java Development Kit (J…...

【GORM】初探gorm模型,字段标签与go案例

GORM是什么&#xff1f; GORM 是一个Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它让我们可以使用结构体来操作数据库&#xff0c;而无需编写SQL 语句 GORM 模型与字段标签详解 在 GORM 中&#xff0c;模型是数据库表的抽象表示&#xff0c;字段标签&am…...

Windows下的Milvus安装秘籍:向量数据库轻松上手

目录 一、简介 二、dockers的安装 1.介绍 2.环境准备 1.启动WSL 的功能。 2.安装并启动Hyper-V Windows10下的安装办法&#xff1a; Windows11下的安装办法&#xff1a; 启动Hyper-V 3.Docker的安装 4、验证是否安装成功 三、安装Milvus 1.Milvus下载 2.Milvus启动…...

在GUI中添加一个Label

标签是一种非常简单的小部件,它可以为我们的图形用户界面(GUI)增添价值。它可以阐释其他组件的用途,提供一些额外的信息,这可以引导用户理解输入框组件的含义,也能够解释那些无需用户输入数据的组件所显示数据的含义。 准备就绪 我们将扩展第一个应用案例,即《创建第一…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...