对CAS的理解

简介: 对CAS的理解

CAS的概念(compare and swap):比较并交换

8891b907eb06e444ed453ebea6afa53f.png

我们首先要明白,自旋是一个纯用户态的操作,本身并没有进行加锁,所执行的代码,是在并发环境下执行的,没有锁。

我们举一个例子来说明自旋加CAS的作用:


121f2075948a065c1371d309d0377ee9.png

9a59e2be2c04aa9f918c4405b6bf4439.png

我们画一个时间图来接着证明:

d8e30d5d2cccd88a39380f32ac689290.png

线程中的Load和CAS的load并不一样,线程中的Load是获取预期值,而CAS中的load是在主内存中获取值,与预期值进行比较,两者作用并不相同。我们发现CAS并不是一个操作,首先要进行预期值和主内存中的值的比较,如果相同再进行下一步的操作,不相同则重新自旋+CAS,伪代码如下,按理说应该对应着许多条cpu指令,但是事实上它只对应着一条cpu指令(cmpxchg),一条指令可以完成所有操作,这条指令对应着系统的一个API,这个API有三个参数:地址值,预期值和要修改的值,但是我们必须要明白的是CAS的实现是通过cpu硬件提供的lock机制保证其原子性,简而言之就是因为硬件层面给予了支持,软件层面才能达到。

1cc607f18944a2709ba8a505342be1da.png

注意:CAS最重要的是判断我们第一次获取到的预期值和主内存中的值是否一致,也就是说数据是否在我们获取完预期值之后被其他线程修改过,没有修改过我们在此基础上进行的修改和写回操作是线程安全的,如果被修改过,此时我们再进行的修改和写回操作可能覆盖之前修改的值,这是线程不安全的。

CAS的两个应用:

①实现自旋锁:

伪代码如下:

9f3edcc02a5e5676e0fbb418bcd8ba17.png

②实现原子类

我们关于原子类的代码如下:

public class demo1001 {

   public static void main(String[] args) throws InterruptedException {

       //创建基于CAS的原子类

       AtomicInteger atomicInteger = new AtomicInteger();

       //创建两个线程实现自增操作

        Thread t1 =new Thread(()->{

            for (int i = 0; i <50000 ; i++) {

                atomicInteger.getAndIncrement();

            }

                });

        Thread t2 =new Thread(()->{

            for (int i = 0; i <50000 ; i++) {

                atomicInteger.getAndIncrement();

            }

                });

        //两个线程均开始执行

       t1.start();

       t2.start();

       //等待两个线程均执行结束

       t1.join();

       t2.join();

       System.out.println(atomicInteger);

   }

}

在这段代码中,我们并没有使用synchronized进行上锁,但是结果仍然是正确8f6ee58ad397d00ae2d6c74000853e11.png

我们查看其源码:


14f7ad08fce08236aa40739f2a3464f1.png

0cd5683d6bc007885fc5dc1ecf582547.png

关于CAS中的ABA问题:

ABA 的问题:

假设存在两个线程 t1 和 t2. 有一个共享变量 num, 初始值为 A.

接下来, 线程 t1 想使用 CAS 把 num 值改成 Z, 那么就需要

先读取 num 的值, 记录到 oldNum 变量中.

使用 CAS 判定当前 num 的值是否为 A, 如果为 A, 就修改成 Z.

但是, 在 t1 执行这两个操作之间, t2 线程可能把 num 的值从 A 改成了 B, 又从 B 改成了 A线程 t1 的 CAS 是期望 num 不变就修改. 但是 num 的值已经被 t2 给改了. 只不过又改成 A 了. 这个时候 t1是否要更新值为Z呢?

那在实际生活中我们举这样一个例子:

52b5053b477c315dec342ac0a6fa4da9.png

虽然从值的大小来看虽然是一样的,但是从操作过程和逻辑上来说有着很大的区别,可以说是两个完全不同的结果,那么我们又该如何解决这个ABA问题呢?

答案很简单,增加一个版本号,当有人对这个数据操作之后,该数据的版本号加1,虽然结果一致,但是我们可以通过版本号来判断这个结果是否是我们期望的结果

c9beafd0d707ed46e498e3d8f215a68a.png


目录
打赏
0
0
0
0
2
分享
相关文章
H3C CAS系列 一、CAS初认识
对于虚拟化,可能第一时间大家想到的是虚拟机,而对于虚拟机大家可能第一时间想到的就是我们大多数人都可能比较熟悉的VMware系列产品,比如常用VMware Workstation Pro 、VMware esxi。 而今天我带大家一起认识一款我们国产的虚拟化软件 H3C CAS。
1806 0
CAS
本文主要讲解java中cas的概念及原理
86 0
|
9月前
|
CAS的超~详细介绍
CAS的超~详细介绍
120 0
CAS存在哪些问题?
CAS存在哪些问题?
263 0
什么是CAS
CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的、开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(属于 Web SSO )。CAS 开始于 2001 年, 并在 2004 年 12 月正式成为 JA-SIG 的一个项目。
497 0
什么是CAS
CAS详解
CAS在底层源码中是使用非常广的,像我之前的HashMap源码解析、volatile详解等文章都有提到CAS。本文将详细介绍CAS。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等