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.mzph.cn/news/240965.shtml

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

相关文章

蓝桥杯第二场小白入门赛(1~5)(对不起,我线段树太菜了)

1.模拟 2.贪心 3.二分 4.数论 5.数论 6.线段树&#xff08;线段树还是练少了...&#xff09; 1. 蓝桥小课堂-平方和 直接模拟&#xff0c;注意数据范围 #include <bits/stdc.h> using namespace std; #define LL long long #define pb push_back #define x first …

低代码开发:数字化转型的引擎

引言 在当今数字化时代&#xff0c;组织面临着不断变化的市场需求和技术挑战。数字化转型已成为维持竞争力的关键&#xff0c;而低代码开发正在崭露头角&#xff0c;成为加速创新和数字化转型的有力工具。本文将深入探讨低代码开发的核心概念、优势和应用&#xff0c;以揭示它…

亚马逊圣诞关键词怎么选?亚马逊圣诞节促销活动有哪些?——站斧浏览器

亚马逊圣诞关键词怎么选&#xff1f; 以下是在亚马逊圣诞期间利用长尾关键词的一些建议&#xff1a; 圣诞主题关键词&#xff1a;随着节日的临近&#xff0c;与圣诞相关的关键词搜索热度将急剧上升。在产品标题、描述、关键词等位置使用与圣诞节相关的关键词&#xff0c;比如…

【数据结构一】初始Java集合框架(前置知识)

Java中的数据结构 Java语言在设计之初有一个非常重要的理念便是&#xff1a;write once&#xff0c;run anywhere&#xff01;所以Java中的数据结构是已经被设计者封装好的了&#xff0c;我们只需要实例化出想使用的对象&#xff0c;便可以操作相应的数据结构了&#xff0c;本篇…

【CentOS 7.9 分区】挂载硬盘为LVM操作实例

LVM与标准分区有何区别&#xff0c;如何选择 目录 1 小系统使用LVM的益处&#xff1a;2 大系统使用LVM的益处&#xff1a;3 优点&#xff1a;CentOS 7.9 挂载硬盘为LVM操作实例查看硬盘情况格式化硬盘创建PV创建VG创建LV创建文件系统并挂载自动挂载添加&#xff1a;注意用空格间…

pip 常用指令 pip list 命令用法介绍

&#x1f4d1;pip 常用命令归类整理 pip list 是一个用于列出已安装的 Python 包的命令。这个命令会显示出所有已安装的包&#xff0c;以及它们的版本号。 pip list 命令有以下参数 -o, --outdated&#xff1a;列出所有过时的包&#xff0c;即有新版本可用的包。-u, --uptod…

3D 纹理贴图基础知识

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 介绍 纹理贴图是创建模型时离不开的最后一块拼图。同样&#xff0c;…

综合评价---DEA数据包络分析

数据包络分析(Data Envelopment Analysis&#xff0c;DEA)&#xff0c;1978年由 Charnes、Cooper和Rhodes创建的一种绩效评价技术(performance technique) 。采用多投入、多产出数据对多个决策单元(Decision Making Unit) 的相对效率进行评价因DEA的诸多优势&#xff0c;被广泛…

【数据结构之顺序表】

数据结构学习笔记---002 数据结构之顺序表1、介绍线性表1.1、什么是线性表? 2、什么是顺序表?2.1、概念及结构2.2、顺序表的分类 3、顺序表接口的实现3.1、顺序表动态存储结构的Seqlist.h3.1.1、定义顺序表的动态存储结构3.1.2、声明顺序表各个接口的函数 3.2、顺序表动态存储…

b2b订货系统成本是多少

批发贸易企业都上b2b订货系统&#xff0c;b2b订货系统成本究竟是多少&#xff0c;今天我们来算一算&#xff0c;尤其是最后一个大家可能会忽略。 一是b2b订货系统模板的功能费用&#xff0c;这部分一般各大厂家是明码标价&#xff0c;比如易订货12800元/年&#xff0c;核货宝首…

深入理解 Rust 中的容器类型及其应用

Rust 作为一种系统编程语言&#xff0c;提供了丰富的容器类型来处理各种数据结构和算法。这些容器类型不仅支持基本的数据存储和访问&#xff0c;还提供了高效的内存管理和安全性保障。本文将详细介绍 Rust 中的几种主要容器类型&#xff0c;包括它们的用法、特点和适用场景&am…

【IDEA】try-catch自动生成中修改catch的内容

编辑器 --> 文件和代码模板 --> 代码 --> Catch Statement Body

【雷达原理】雷达测速原理及实现方法

一、雷达测速原理 1.1 多普勒频率 当目标和雷达之间存在相对运动时&#xff0c;若雷达发射信号的工作频率为&#xff0c;则接收信号的频率为&#xff0c;其中为多普勒频率。将这种由于目标相对于辐射源运动而导致回波信号的频率发生变化的现象称为多普勒效应。 如图1-1所示&a…

优先级队列与仿函数

优先级队列 优先级队列 priority_queue 是一种容器适配器&#xff0c;听起来是队列&#xff0c;其实它的底层数据结构是堆&#xff0c;所谓的优先级为默认越大的数优先级越高&#xff0c;即默认为大堆。 使用方式如下面的代码&#xff1a; #include<iostream> #includ…

攻防世界——game 游戏

下载下来是一个exe文件&#xff0c;可以用IDA打开 我们先运行一下 这是属于第二种类型&#xff0c;完成一个操作后给你flag 这种题我更倾向于动调直接得到flag 我们查壳 没有保护壳&#xff0c;直接32打开 进入字符串界面&#xff0c;找到显示的那部分 int __cdecl main_0(…

Java经典面试题——手写快速排序和归并排序

题目链接&#xff1a;https://www.luogu.com.cn/problem/P1177 输入模板&#xff1a; 5 4 2 4 5 1快速排序 技巧&#xff1a;交换数组中的两个位置 a[l] a[l] a[r] - (a[r] a[l]); 稳定不稳定&#xff1f;:不稳定 注意找哨兵那里内循环的等于号不能漏&#xff0c;不然…

MyBatis的ORM映射

目录 什么是ORM 一&#xff0c;列的别名 二&#xff0c;结果映射 三&#xff0c;总结 什么是ORM ORM&#xff1a;对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM&#xff09;模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简…

力扣思维题——寻找重复数

题目链接&#xff1a;https://leetcode.cn/problems/find-the-duplicate-number/description/?envTypestudy-plan-v2&envIdtop-100-liked 这题的思维难度较大。一种是利用双指针法进行计算环的起点&#xff0c;这种方法在面试里很难说清楚&#xff0c;也很难想到。大致做…

idea structure视图介绍

作用 idea的Structure视图可以辅助查看代码结构 如何呼出Structure视图&#xff1f; Alt 7 Ctrl F12 侧边栏点Structure 我的常用配置 1、选Show Toolbar&#xff0c;便于使用功能按钮 2、使用Float视图&#xff0c;悬浮于窗口表面&#xff0c;可以使用 ShiftEsc来退出…

quic协议及核心源码分析

quic协议 1、网络通信时&#xff0c;为了确保数据不丢包&#xff0c;早在几十年前就发明了tcp协议&#xff01;然而此一时非彼一时&#xff0c;随着技术进步和业务需求增多&#xff0c;tcp也暴露了部分比较明显的缺陷&#xff0c;比如: 建立连接的3次握手延迟大&#xff1b; T…