CAS机制

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

文章目录

    • 1、什么是CAS?
    • 2、CAS实现原子操作的3大问题?
    • 3、Unsafe类
    • 4、AtomicReference``
    • 5、CAS——自旋锁

1、什么是CAS?

CAS的全称是 Compare And Swap(比较再交换,确切一点称之为:比较并且相同再做交换)
是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令。CAS的作用是:CAS可以将比较和交换转换为原子操作,这个原子操作直接由处理器CPU保证。

(可以看做是一个轻量级的synchronized,它能保证变量修改的原子操作)

CAS指令需要有三个操作数,分别是:

  • 内存位置(在Java中可以简单地理解为变量的内存地址,用V表示)
  • 旧的预取值(用A表示)
  • 准备设置的新值(用B表示)
    在这里插入图片描述
    CAS指令执行时,当且仅当 V 符合 A 时,处理器才会用 B 更新 V 的值,否则它就不执行更新 或 重来(当他重来重试的这种行为称为——自旋)。但是不管是否更新了 V 的值,都会返回 V 的旧值。该过程是一个原子操作,执行期间不会被其他线程中断。

它是一种CPU并发原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。

说了这么多原理,撸一下Demo吧~通过实现类AtomicInteger来演示一下CAS:

public class CASDemo {public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(6);System.out.println(atomicInteger.compareAndSet(6, 2022) + "\t" + atomicInteger.get());System.out.println(atomicInteger.compareAndSet(6, 2022) + "\t" + atomicInteger.get());}
}

在这里插入图片描述

第一次C的值等于A,故将C改为B。第二次C得值不等于A,故不修改。

2、CAS实现原子操作的3大问题?

ABA问题、循环时间长消耗资源大、只能保证一个 共享变量的原子操作。

循环时间长消耗资源大

比如说源码 getAndAddInt方法执行时,有个 do while。如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。

ABA 问题

​ 如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然为 A 值,那就能说明它的值没有被其他线程改变过了吗?

​ 这是不可能的,因为 如果在这段期间它的值曾经被改成 B,后来又被改回为 A,那CAS操作就会误人误它从来没有被改变过。这个漏洞称为 CAS 操作的 “ABA问题”。接下来个Demo~

public class ABADemo {static AtomicInteger atomicInteger = new AtomicInteger(100);public static void main(String[] args) {new Thread(()->{atomicInteger.compareAndSet(100,200);// 暂停10毫秒try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();} finally {atomicInteger.compareAndSet(200,100);}},"t1").start();new Thread(()->{// 暂停200毫秒try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(atomicInteger.compareAndSet(100,500) + "\t" + atomicInteger.get());}},"tw").start();}
}

代码中 t1线程将值修改为200,但又在t2线程读取之前修改为100。但t1线程不知道呀,就会误人误它从来没有被改变过。

那么如何解决ABA问题呢?可以使用java.util.concurrent.atomic.AtomicStampedReference<V>类来解决

public class ABADemo {static AtomicInteger atomicInteger = new AtomicInteger(100);static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);public static void main(String[] args) {new Thread(()->{int stamp = stampedReference.getStamp();System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);// 暂停500毫秒,保证后面的t2线程初始化拿到的版本号和t1一样try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}stampedReference.compareAndSet(100, 200, stampedReference.getStamp(), stampedReference.getStamp()+1);System.out.println(Thread.currentThread().getName()+"\t"+"2次版本号:"+stampedReference.getStamp());stampedReference.compareAndSet(200,100,stampedReference.getStamp(), stampedReference.getStamp()+1);},"t1").start();new Thread(()->{int stamp = stampedReference.getStamp();System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);// 暂停1000毫秒,保证t2线程初始化拿到的版本号和t1一样try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}boolean b = stampedReference.compareAndSet(100, 500, stamp, stampedReference.getStamp() + 1);System.out.println(b + "\t" + stampedReference.getReference() + "\t" + stampedReference.getStamp());},"t2").start();}
}

3、Unsafe类

从 JDK5 之后,Java类库中才开始使用CAS操作,该操作由 sun.misc.Unsafe 类里面的 compareAndSwapXXX()方法包底层实现即为CPU指令cmpxchg。

执行 cmpxchg 指令的时候,会判断当前系统是否为多核系统,如果是就给总线加锁,只有一个线程会对总线加锁成功,加锁成功会执行CAS操作,也就是说CAS的原子性实际上是CPU实现独占的。

Unsafe类详解

在这里插入图片描述

1、Unsafe

​ 是CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。

注意:Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都是直接调用操作系统底层资源执行相应任务。

2、变量valueOffset,表示该变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的。

3、变量value用volatile修饰,保证了多线程之间的内存可见性。

源码解读

接下来我们来分析一下源代码:

public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

通过点进compareAndSet() 方法的源代码,发现其是调用了unsafe.compareAndSwapInt()方法,在unsafe类中,主要有以下三个方法:

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

上面三个方法都是类似的,主要对4个参数做一下说明:

  • var1:表示要操作的对象
  • var2:表示要操作对象中属性地址的偏移量
  • var4:表示需要修改数据的期望的值
  • var5/var6:表示需要修改为的新值

这里对偏移量做一下讲解,大学汇编里有说过~this 相当于当前对象的首地址,需要找到对应的value在内存中的存放位置,此时就需要一个偏移量,即:收地址+偏移量=值在内存中的位置

我们已知i++在多线程情况下是不安全的,那 atomicInteger.getAndIncrement() 方法呢?

在这里插入图片描述

假设线程A和现场B两个线程同时执行 getAndIncrement()方法(分别跑在不同CPU上):

  1. 假设主内存中 value原始值为3,根据JMM模型,线程A 和 线程B各自持有一份值为3的value的副本分别到各自的工作内存。
  2. 线程A通过getIntVolatile(var1, var2)拿到value值3,假设这时线程A被挂起。
  3. 线程B也通过getIntVolatile(var1, var2)拿到value值3,此时线程B没有被挂起并执行 compareAndSwapInt 方法,比较内存值也为3,则成功修改内存值为4,线程B执行完毕。
  4. 此时线程A被唤醒,执行compareAndSwapInt 方法比较,发现主内存中的值和旧的预期值不一致,说明该值已经被其他线程更新了,则线程A本次修改失败,自旋重来一次。
  5. 线程A重新获取value值,因为变量value被volatile修饰,所以其他线程对它的修改,线程A是可见的,线程A继续执行 compareAndSwapInt 进行比较替换,直到成功为止。

Unsafe类中的compareAndSwapInt,对应着本地方法,该方法的实现位于unsafe.cpp,让我们一探究竟~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xilwh0X8-1656433185456)(JUC并发编程.assets/image-20220628234302944.png)]

4、AtomicReference<V>

  1. AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。

  2. AtomicReference是作用是对”对象”进行原子操作。 提供了一种读和写都是原子性的对象引用变量。原子意味着多个线程试图改变同一个AtomicReference(例如比较和交换操作)将不会使得AtomicReference处于不一致的状态。

即 可以原子更新的对象引用。

首先编写一个User类:

class User{String username;int age;// 省略全参构造方法、setter、getter、toString
}

通过AtomicReference类实现对”User对象”进行原子操作。

public class AtomicReferenceDemo {public static void main(String[] args) {AtomicReference<User> userAtomicReference = new AtomicReference<>();User hgw = new User("hgw", 22);User hly = new User("hly", 22);userAtomicReference.set(hly);System.out.println(userAtomicReference.compareAndSet(hly, hgw) +"\t,"+ userAtomicReference.get());System.out.println(userAtomicReference.compareAndSet(hly, hgw) +"\t,"+ userAtomicReference.get());}
}

5、CAS——自旋锁

谈CAS的话当然得谈谈自旋锁啦,这边手写个自旋锁给大家演示一下吧~

public class SpinLockDemo {AtomicReference<Thread> atomicReference = new AtomicReference<>();public void lock() {Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"\t"+"----come in");while (!atomicReference.compareAndSet(null, thread)) {}System.out.println(Thread.currentThread().getName()+"\t"+"lock");}public void unLock() {Thread thread = Thread.currentThread();atomicReference.compareAndSet(thread,null);System.out.println(Thread.currentThread().getName()+"\t"+"----task over,unLock...");}public static void main(String[] args) {SpinLockDemo spinLockDemo = new SpinLockDemo();new Thread(()->{spinLockDemo.lock();// 暂停几秒钟线程try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();} finally {spinLockDemo.unLock();}},"A").start();new Thread(()->{spinLockDemo.lock();spinLockDemo.unLock();},"B").start();}
}

在这里插入图片描述


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

相关文章

Java 中 CAS 是什么,有哪些实际应用场景

CAS 是什么 CAS&#xff08;Compare And Swap&#xff09;是一种并发编程中的原子操作&#xff0c;用于实现多线程之间的同步。在 Java 中&#xff0c;CAS 操作通过 sun.misc.Unsafe 类实现。 CAS 操作是一种乐观锁机制&#xff0c;它假设对于共享变量的修改操作不会引起冲突…

Java 什么是 CAS? 通俗易懂

Java 并发机制实现原子操作有两种&#xff1a; 一种是锁&#xff0c;一种是CAS。 CAS是Compare And Swap&#xff08;比较并替换&#xff09;的缩写。 java.util.concurrent.atomic中的很多类&#xff0c;如&#xff08;AtomicInteger AtomicBoolean AtomicLong等&#xff09;都…

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

文章目录 什么是CASCAS 举例说明CAS 底层实现CAS缺陷 什么是CAS CAS 的全称是 Compare And Swap 即比较交换&#xff0c;其算法核心思想如下函数&#xff1a;CAS(V,E,N) 参数&#xff1a; V 表示要更新的变量E 预期值N 新值 如果 V 值等于 E 值&#xff0c;则将 V 的值设为 …

【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中的一条命令 红队团队合作模拟…