JavaEE:CAS详解

一.什么是CAS

CAS: 全称 Compare and swap ,字面意思 :” 比较并交换 ,一个 CAS 涉及到以下操作:
 我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。
我们来进行操作:
1. 比较 V 和 A 是否相等。(比较)
2. 如果比较是相等的,将B 写入 V。(交换)
3. 返回操作是否成功。
伪代码如下:
boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue) {&address = swapValue;return true;}return false;
}

这个就大概介绍了CAS的工作流程

二.CAS是如何实现的

针对不同的操作系统,JVM用到了不同的CAS实现原理

  • java CAS 利用的的是 unsafe 这个类提供的 CAS 操作;
  • unsafe CAS 依赖了的是 jvm 针对不同的操作系统实现的 Atomic::cmpxchg
  • Atomic::cmpxchg 的实现使用了汇编的 CAS 操作,并使用 cpu 硬件提供的 lock 机制保证其原子性。

三.CAS的应用

1.实现原子类

我们都知道,在多线程环境下,我们的++操作不是线程安全的。那么我们的CAS就自己将 ++ 操作是现成了原子类。

import java.util.concurrent.atomic.AtomicInteger;public class CAS {public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(0);int ret = atomicInteger.incrementAndGet();System.out.println(ret);}
}

此时在Java中,为我们提供了这样的 ++ 原子类操作。以上代码的运行结果为 1 。

那么我们深究一下这其中的实现原理

先来看下面的伪代码:

class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {oldValue = value;}return oldValue;}
}

首先要知道我们的CAS操作时原子的。在多线程环境下,那么他是如何保证每次读到的值,都是我们预期的值呢?

我们看下面的图片:

🎈第一步

两个线程都读取 value 的值到 oldValue . (oldValue 是一个局部变量, 在栈上. 每个线程有自己的栈)

🎈第二步

线程1进行CAS操作,先进行比较,发现 oldValue 和 Value 都是相同的,然后进行oldValue+1操作,最后再写入到内存中。此时主内存中Value的值为 1

🎈第三步

此时线程2进行操作。再进行 比较 oldValue 和 Value 是否相同的时候,发现不相同。此时重新进入while循环!在循环的时候, 会刷新oldValue的值-->1,此时oldValued 和 Value的值就相同了。正常进行+1赋值操作。

🎈第四步

线程 1 和 线程 2 返回各自的 oldValue 的值即可
我们可以很清楚的看到,CAS使用while循环巧妙的解决了++操作的线程安全问题。

2.实现自旋锁

先来看自旋锁的伪代码:

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

自旋锁其实时一种锁的策略,它的实现原理就是如果当前的线程是有锁的,那么就一直while循环尝试获取锁,如果没锁了,那么就直接可以获取到CPU了。

四.CAS的ABA问题

我们先来看个例子:

假如我要去银行里取钱,我的存款是100元,我期望的是取出50元。

那么取款机创建了两个线程,假如线程1执行了-50的操作,线程2再执行的时候会报错。

1.正常的过程

1) 存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期
望更新为 50.
2) 线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
3) 轮到线程2 执行了, 发现当前存款为 50, 和之前读到的 100 不相同, 执行失败.

2.异常的过程

1) 存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期
望更新为 50.
2) 线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
3) 在线程2 执行之前, 我的朋友正好给滑稽转账 50, 账户余额变成 100 !!
4) 轮到线程2 执行了, 发现当前存款为 100, 和之前读到的 100 相同, 再次执行了扣款操作!
那么此时就执行了两次扣款操作,这显然不是我们所期望的。

3.解决办法

给要修改的值 , 引入版本号 . CAS 比较数据当前值和旧值的同时 , 也要比较版本号是否符合预期
版本号随着每次的使用而进行更新
还是刚才银行取钱的案例
为了解决 ABA 问题, 给余额搭配一个版本号 , 初始设为 1.
1) 存款 100. 线程1 获取到 存款值为 100, 版本号为 1, 期望更新为 50; 线程2 获取到存款值为 100,
版本号为 1, 期望更新为 50.
2) 线程1 执行扣款成功, 存款被改成 50, 版本号改为2. 线程2 阻塞等待中.
3) 在线程2 执行之前, 滑稽的朋友正好给滑稽转账 50, 账户余额变成 100, 版本号变成3.
4) 轮到线程2 执行了, 发现当前存款为 100, 和之前读到的 100 相同, 但是当前版本号为 3, 之前读
到的版本号为 1, 版本小于当前版本, 认为操作失败.
此时引入了版本号,ABA问题就完美的得到了解决。

总结:CAS是面试中常考的问题,我们需要深度学习,并且理解其中的操作机制。

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/224586.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3 全局配置Axios实例

目录 前言 配置Axios实例 页面使用 总结 前言 Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。它提供了一种简单、一致的 API 来处理HTTP请求,支持请求和响应的拦截、转换、取消请求等功能。关于它的作用: 发起 HTTP …

VMware虚拟机安装Ubuntu系统教程

所使用的文件如下: VMware Workstation 17 Pro ubuntu-22.04.3-desktop-amd64.iso 一、ubuntu 命名规则及各版本一览表 1.ubuntu 命名规则: 例如:ubuntu 16.04 LTS 是长期维护版本;ubuntu 17.04 是新特性版本 前两位数字为发…

使用pytorch神经网络拟合计算模型

一. 内容简介 python调用百度翻译api,将中文论文翻译英文,并保留部分格式 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3数据文件 链接:https://pan.baidu.com/s/1csJOoErGyx77MW_FImVKjg?pwd1234 三.主要流程 3.…

【计数DP】牛客小白月赛19

登录—专业IT笔试面试备考平台_牛客网 题意 思路 首先做法一定是计数 dp 然后状态设计,先设 dp[i] 然后看影响决策的因素:两边的火焰情况,那就 dp[i][0/1][0/1]表示 前 i 个,该位有无火焰,该位右边有无火焰的方案数…

mysql原理--连接查询的成本

1.准备工作 连接查询至少是要有两个表的,只有一个 single_table 表是不够的,所以为了故事的顺利发展,我们直接构造一个和 single_table 表一模一样的 single_table2 表。为了简便起见,我们把 single_table 表称为 s1 表&#xff0…

ES8生产实践——Kibana对接Azure AD实现单点登录

基本概念介绍 什么是单点登录 单点登录(Single Sign-On,SSO)是一种身份验证和访问控制机制,允许用户使用一组凭据(通常是用户名和密码)仅需登录一次,即可访问多个应用程序或系统,而…

结构体的对齐规则

1.引入 我们在掌握了结构体的基本使⽤后。 现在我们深⼊讨论⼀个问题:计算结构体的大小。 这也是⼀个特别热门的考点: 结构体内存对齐。 2.具体分析 ⾸先我们得掌握结构体的对⻬规则: 1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量…

一站式指南:第 377 场力扣周赛的终极题解

比赛详情 比赛地址 题目一很简单题目二主要是题目长了点,其实解法很常规(比赛后才意识到)题目三套用Dijkstra算法题目四没时间解答水平还有待提升(其实就是需要灵活组合运用已知的算法,有点类似大模型的Agent) 题解和思路 第一题:最小数字…

CentOS进入单用户模式

一、重启 二、出现内核选项 按“e” 三、编辑这一行 输入 rw init/sysroot/bin/sh 四、进入单用户模式 ctrlx 进入 五、切换目录 chroot /sysroot 六、然后你就操作你的系统了。 修改密码等等

【知识点随笔分享 | 第九篇】常见的限流算法

目录 前言: 1.固定窗口限流: 缺点: 2.滑动窗口限流: 优点: 滴桶限流: 缺点: 令牌桶限流: 优点: 总结: 前言: 当今互联网时代,随着网络…

IP编址,IP地址介绍与子网划分方法

网络层位于数据链路层与传输层之间。网络层中包含了许多协议,其中最为重要的协议就是IP协议。网络层提供了IP路由功能。理解IP路由除了要熟悉IP协议的工作机制之外,还必须理解IP编址以及如何合理地使用IP地址来设计网络。 上层协议类型 以太网帧中的Typ…

数据通信网络基础华为ICT网络赛道

目录 前言: 1.网络与通信 2.网络类型与网络拓扑 3.网络工程与网络工程师 前言: 数据通信网络基础是通信领域的基本概念,涉及数据传输、路由交换、网络安全等方面的知识。华为ICT网络赛道则是华为公司提出的一种技术路径,旨在通…

主机安全技术措施

目录 身份鉴别 进阶 访问控制 进阶 安全审计 进阶 ​编辑 剩余信息保护 入侵防范 进阶 恶意代码防范 资源控制 身份鉴别 进阶 访问控制 进阶 安全审计 进阶 剩余信息保护 入侵防范 进阶 恶意代码防范 资源控制 ~over~

Git 分布式版本控制系统(序章1)

第一章 Git 分布式版本控制系统 为什么学Git? 某些企业面试需要掌握Git,同时,也方便管理自己的Qt项目。 一、Git 客户端下载(Windows) 下载地址 https://gitee.com/all-about-git#git-%E5%A4%A7%E5%85%A8 二、Git 的特点 分支…

java的XWPFDocument3.17版本学习

maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version> </dependency> 测试类&#xff1a; import org.apache.poi.openxml4j.exceptions.InvalidFormatExcep…

【MybatisPlus快速入门】(3)SpringBoot整合MybatisPlus 之 Lombok插件安装及MybatisPlus分页代码示例

目录 1.Lombok1.1 步骤1:添加lombok依赖 2.2 步骤2:安装Lombok的插件1.3 步骤3:模型类上添加注解2 分页功能2.1 步骤1:调用方法传入参数获取返回值2.2步骤2:设置分页拦截器2.3 步骤3:运行测试程序 之前我们已学习MyBatisPlus在代码示例与MyBatisPlus的简介&#xff0c;在这一节…

Web Components入门不完全指北

目前流行的各类前端框架&#xff0c;不管是react, angular还是vue&#xff0c;都有一个共同点&#xff0c;那就是支持组件化开发&#xff0c;但事实上随着浏览器的发展&#xff0c;现在浏览器也原生支持组件式开发&#xff0c;本文将通过介绍Web Components 的三个主要概念&…

vue场景 无分页列表条件过滤,子组件多选来自父组件的列表

日常开发中&#xff0c;经常会遇到下面场景&#xff1a; 页面加载一个无分页列表&#xff0c;同时工具栏设置多个条件可对列表过滤的场景(典型的就是关键字模糊查询)父组件传给子组件列表&#xff0c;子组件中需要多选列表多选&#xff0c;选择结果返回父组件 1 无分页列表过…

电子电器架构刷写方案——General Flash Bootloader

电子电器架构刷写方案——General Flash Bootloader 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 注&#xff1a;文章1万字左右&#xff0c;深度思考者入&#xff01;&#xff01;&#xff01; 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免…

CentOS 7 Tomcat服务的安装

前提 安装ava https://blog.csdn.net/qq_36940806/article/details/134945175?spm1001.2014.3001.5501 1. 下载 wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.84/bin/apache-tomcat-9.0.84.tar.gzps: 可选择自己需要的版本下载安装https://mirr…