什么是CAS?CAS有什么缺点?

article/2025/9/29 15:49:45

文章目录

    • 什么是CAS
    • CAS 举例说明
    • CAS 底层实现
    • CAS缺陷

什么是CAS

CAS 的全称是 Compare And Swap 即比较交换,其算法核心思想如下函数:CAS(V,E,N) 参数:

  1. V 表示要更新的变量
  2. E 预期值
  3. N 新值

如果 V 值等于 E 值,则将 V 的值设为 N。若 V 值和 E 值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。

通俗的理解就是 CAS 操作需要我们提供一个期望值,当期望值与当前线程的变量值相同时,说明还没线程修改该值,当前线程可以进行修改,也就是执行 CAS 操作,但如果期望值与当前线程不符,则说明该值已被其他线程修改,此时不执行更新操作,但可以选择重新读取该变量再尝试再次修改该变量,也可以放弃操作。

我们看一下例子:

  1. 在内存地址V当中,存储这值为10的变量

在这里插入图片描述
2. 此时线程1想要把变量的值增加1。对于线程1来说,旧的预期值为E=10,要修改的值 N=11。
在这里插入图片描述
3. 线程1要提交更新之前,另一个线程2抢先一步,把内存地址V的变量值先更改成了11

在这里插入图片描述
4. 线程1开始提交更新,首先进行E和内存V中实际值比较,发现E不等于V的实际值,提交失败。

在这里插入图片描述
5. 线程1重新获取内存地址V的当前值,并重新计算想要修改的新值,此时对线程1来说,E=11,N=12。这个重新尝试的过程被称为自旋。

在这里插入图片描述
6. 这一次没有发现其他线程改变地址V的值。线程1进行Compare ,发现N和地址V的实际值是相等的。

在这里插入图片描述
7.线程1进行swap,把地址V的值替换为N ,也就是12.

在这里插入图片描述

CAS 举例说明


public static int count = 0;public static void main(String[] args) {//for (int i=0;i<5;i++){new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(1000);}catch (Exception e){}//每个线程当中让count值自增100次for(int j=0;j< 10000;j++){count++;}}}).start();}try{Thread.sleep(2000);}catch (Exception e){}System.out.println("count=="+count);
}

如上示例程序,因为上面代码不是线程安全的,所以最终的结果可能会小于 50000。

那么怎么解决呢?可以加锁(synchronized)。

 public static int count = 0;public static void main(String[] args) {//for (int i=0;i<5;i++){new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(1000);}catch (Exception e){}//每个线程当中让count值自增100次for(int j=0;j< 10000;j++){synchronized (Demo1.class) {count++;}}}}).start();}try{Thread.sleep(2000);}catch (Exception e){}System.out.println("count=="+count);
}

加了同步锁以后,count自增的操作变成了原子性操作,所以最终的输出一定是count = 50000。

Synchronized 的确保证了线程安全,但是在某些情况下,却不是一个最优选择。

为什么这么说?关键在于性能问题

Synchronized 关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLED状态,这个过程中设计到的操作系统用户模式和内核模式,代价比较高。

尽管jdk1.6 为Synchronized做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低

java原子操作类,指的是java.util.concurrent.atomic包下,一些列以Atomic开头的包装类。例如AtomicBoolean、AtomicInteger、AtomicLong。他们分别用于boolean、Integer、Long类型的原子性操作。

现在我们尝试在代码中引入**AtomicInteger **类:

 public static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) {//for (int i=0;i<5;i++){new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(1000);}catch (Exception e){}//每个线程当中让count值自增100次for(int j=0;j< 10000;j++){synchronized (Demo1.class) {count.incrementAndGet();}}}}).start();}try{Thread.sleep(2000);}catch (Exception e){}System.out.println("count=="+count.get());
}

使用AtomicInteger之后,最终的输出结果同样可以保证是50000。并且在某些情况下,代码的性能会比Synchronized更好。

Atomic 操作类的底层,正是利用了CAS机制;

CAS 底层实现

下面看一下AtomicInteger的源代码

public final int incrementAndGet() {for (;;) {int current = get();int next = current + 1;if (compareAndSet(current, next))return next;}
}private volatile int value;
public final int get() {return value;
}

这段代码是一个无限循环,也就是CAS的自旋。循环体当中做了三件事:

  1. 获取当前值
  2. 当前值+1,计算出目标值
  3. 进行CAS操作,如果成功则跳出循环,如果失败则重复上述步骤

这里需要注意的重点是get方法,这个方法的作用是获取变量的当前值。

如何保证获得的当前值时内存中的最新值呢?很简单,用volatile关键字来保证,

可是compareAndSet方法是如何保证原子性操作的呢??

接下来看一看compareAndSet方法的实现,以及方法所依赖对象的来历:
在这里插入图片描述
compareAndSet方法的实现很简单,只有一行代码。这里涉及到两个重要的对象,一个是unsafe,一个是valueOffset

**什么是unsafe呢?**Java语言不像C,C++那样可以直接访问底层操作系统,但是JVM为我们提供了一个后门,这个后门就是unsafe。unsafe为我们提供了硬件级别的原子操作。

至于valueOffset对象,是通过unsafe.objectFieldOffset方法得到,所代表的是AtomicInteger对象value成员变量在内存中的偏移量。我们可以简单地把valueOffset理解为value变量的内存地址。

而unsafe的compareAndSwapInt方法参数包括了这三个基本元素:valueOffset参数代表了V,expect参数代表了A,update参数代表了B。

正是unsafe的compareAndSwapInt方法保证了Compare和Swap操作之间的原子性操作。

CAS缺陷

1.ABA 问题

因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。举个通俗点的例子,你倒了一杯水放桌子上,干了点别的事,然后同事把你水喝了又给你重新倒了一杯水,你回来看水还在,拿起来就喝,如果你不管水中间被人喝过,只关心水还在,这就是ABA问题。
如果你是一个讲卫生讲文明的小伙子,不但关心水在不在,还要在你离开的时候水被人动过没有,因为你是程序员,所以就想起了放了张纸在旁边,写上初始值0,别人喝水前麻烦先做个累加才能喝水。

2.循环时间长 开销大

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销

2.只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子
性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作


http://chatgpt.dhexx.cn/article/MDktjiMx.shtml

相关文章

【ceph】存储领域的CAS是什么?什么是CAS|Open CAS|缓存加速软件

目录 什么是CAS 出现原因和应用场景&#xff1a; 初始Open CAS What SPDK Block Device Open CAS Linux Whats Cache? Whats Cache Object? Cache operations Cache Configuration Cache Mode Cache line size Whats Core? Whats Cache line&#xff1f; Cach…

java常见面试考点(二十五):CAS是什么

java常见面试考点 往期文章推荐&#xff1a;   java常见面试考点&#xff08;二十&#xff09;&#xff1a;Elasticsearch 和 solr 的区别   java常见面试考点&#xff08;二十一&#xff09;&#xff1a;单点登录   java常见面试考点&#xff08;二十二&#xff09;&…

CAS是什么?彻底搞懂CAS

CAS&#xff08;Compare-And-Swap&#xff09;,它是一条CPU并发原语&#xff0c;用于判断内存中某个位置的值是否为预期值&#xff0c;如果是则更改为新的值&#xff0c;这个过程是原子的。 CAS基本原理 CAS并发原语体现在Java中就是sun.misc.Unsafe类中的各个方法。调用UnSa…

(一)CAS是什么?

前言 随着企业数字化转型的不断发展&#xff0c;应用系统越来越多&#xff0c;每个系统都有一套用户系统&#xff0c;用户在操作不同的系统时&#xff0c;需要多次登录&#xff0c;而且每个系统的账号都不一样&#xff0c;这对于用户来说&#xff0c;很不方便。这时候要做到 在…

CAS是什么

目录 没有CAS之前 使用CAS之后 CAS是什么 CAS底层原理&#xff1a;unsafe类 Unsafe new AtomicInteger().getAndIncrement()流程 CAS缺点 1 循环时间长开销很大 2 ABA问题 ABA代码演示 如何解决&#xff1f;&#xff1a;通过AtomicStampedReference版本号 3不能保…

CAS 是什么?

CAS又称 自旋锁、无锁&#xff0c;是一种乐观锁 compare and swap 的缩写 意为: 比较并交换 , 实现并发算法的常用技术 , 就是说我不用加锁 , 也能保证 ( 加锁会影响效率&#xff0c;可以考虑使用原子操作类 ) 原子性 , 当多个线程尝试使用 CAS 同时更新同一个变量时&#xf…

什么是CAS

文章目录 一、CAS是什么二、CAS 可以解决什么问题三、CAS实现原子操作的问题 一、CAS是什么 CAS的全称为compare and swap 或者compare and exchange,意思为比较和交换。CAS流程如下&#xff1a; 假设我们有一个共享变量i&#xff0c;初始值为0。我们现在要对i进行加1的操作…

metasploit图形化工具 Armitage

Metasploit默认使用PostgreSQL存储渗透测试所需的数据表&#xff0c;所以在启动Armitage之前需要首先启动PostgreSQL服务和Metasploit服务&#xff0c;然后再启动armitage&#xff0c;弹出对话框询问是否连接Metasploit的RPC信道&#xff0c;依次选择“connect”、“是”选项。…

ARM..

一 关于arm 1 arm的三种含义 (1) 一个公司的名称 Advanced RISC Machine (2) 一类处理器的统称 (3) 一种技术的名称 &#xff08;RISC&#xff09; ARM是以一家设计处理器的公司&#xff0c;这家公司设计的处理器统称为ARM&#xff0c;它们使用的指令集是RISC&#xff08;精简指…

01-Introducing the Arm architecture

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈目录 1、Overview2、About the Arm architecture3、架构(architecture)到底是什么意思呢

傻瓜式渗透Armitage的使用

目录 Armitage的基本介绍 安装 1 启动Armitage 1、Armitage启动前初始化&#xff1a; 2、Armitage启动的三种方法&#xff1a; 2 使用Armitage生成被控端和主控端 1、Armitage的工作界面&#xff1a; &#xff08;1&#xff09;区域1&#xff1a; &#xff08;2&#…

Kali Linux Armitage生成被控端和主控端

目录 说明使用 Armitage生成被控端和主控端 说明 按照《Kali Linux2 网络渗透测试实践指南 第二版 》第八章操作 仅供学习讨论使用&#xff0c;请勿进行非法操作 使用 Armitage生成被控端和主控端 选中“payload”&#xff0c; 然后选择“windows” ➡️“meterpreter”&…

[architecture]-arm exclusive机制介绍

关键词:spinlock,原子操作,独占访问,exclusive,inclusive,mutex,Semaphore,互斥,同步,同步原语 快速链接: . &#x1f449;&#x1f449;&#x1f449; 个人博客笔记导读目录(全部) &#x1f448;&#x1f448;&#x1f448; 付费专栏-付费课程 【购买须知】: 【精选】ARMv8/…

使用Armitage进行渗透测试与键盘记录

0x00&#xff1a;Armitage是一款基于GUI开发的图形化渗透工具&#xff0c;对于渗透测试而言能够快速了解网络的拓扑以及主机状态&#xff0c;其功能丰富&#xff0c;是每一位渗透测试者的必备武器&#xff1b;今天我就来演示如何在Armitage下入侵纯在漏洞的XP系统&#xff0c;废…

在2022年的kali linux上面安装armitage

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 在2022年的kali linux上面安装armitage 前言一、armitage是什么&#xff1f;二、安装步骤1.官网下载2.build安装3.配置数据库 总结 前言 提示&#xff1a;在2022年的kali li…

ARMv8 architecture里的Memory aborts

在AArch64 Virtual Memory System Architecture中&#xff0c;有以下几种机制会导致PE在访问memory失败时产生exceptions。 Debug exception: An exception caused by the debug configuration.Alignment fault: An Alignment fault is generated if the address used for a m…

Armitage图形化前端

开源免费图形前端 ● 作者自称是众多不会使用metasploit的安全专家之一&#xff08;命令行&#xff09; ● MSF基于命令行&#xff0c;缺少直观的GUI图形用户接口 Armitage只是调用MSF的漏洞利用能力 ● Armitage的每一个GUI操作都可以对应MSF中的一条命令 红队团队合作模拟…

Kali Linux 使用Armitage

目录 说明安装扫描网络Quick Scan (OS detect)输入网段扫描结果 图形化ms17_010先扫描 auxiliary再攻击被渗透图形化metaspliotMeterpreter 5类任务&#xff1a;计算系统密码的hash值 Browser filesLog Keystrokes 写在最后 Armitage是一款用Java为Metasploit编写的图形化操作界…

【Arm架构】什么是Arm?

1 Arm architecture Arm 架构是世界上最流行的处理器架构之一。每年有数十亿台基于 Arm 的设备出货。 A-Profile (Applications) R-Profile (Real-Time) M-Profile (Microcontroller) 高性能场景 实时系统 小型&#xff0c;高能效设备 用于运行复杂的操作系统&#xff0…

「Arm Arch」 初识 Arm

本文源自《书香度年华》「ARM 架构专栏」&#xff0c;是一系列由浅入深、循序渐进的文章&#xff0c;文章之间有一定的前后关联性&#xff0c;所以按顺序阅读&#xff0c;建议收藏专栏。 目录 前言 一、架构概述 1.1 冯诺依曼架构 1.2 哈佛架构 1.3 Arm 架构 二、架构图谱…