前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解 CAS 及 ABA问题

深入理解 CAS 及 ABA问题

作者头像
用户2141593
发布2019-02-20 11:09:17
7960
发布2019-02-20 11:09:17
举报
文章被收录于专栏:Java进阶Java进阶

CAS,Compare And Swap,即比较并交换。

CAS是Atomic 包的核心,更是整个J.U.C 包的 基石。

本文 将通过AtomicInteger这个类,来分析是如何通过CAS来保证 Atomic的原子性的。

直接进入 AtomicInteger 这个类,可以看到

AtomicInteger 中定义了一个变量value并且用 valatile来修饰的, 还有个静态代码块 的 valueOffset变量可以得到 这个value的值。

所以我们在初始化 AtomicInteger 这个类,并设值后,调用 AtomicInteger  的其它方法,就是用的这个 valueOffset来接收了

然后进入 AtomicInteger 的 incrementAndGet 方法,该方法是 默认 +1 操作。

代码语言:javascript
复制
public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

this 当前类,没什么好说的,

    valueOffset ,就是此时 AtomicInteger 类保存的 value 值。

    进入 该方法的实现

代码语言:javascript
复制
 public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);   //从主存中 去拿这个变量最新的值
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

分析如下:如果当前value 的值是 5,那么进行 5 + 1 这个操作

var1 是当前的AtomicInteger 这个类

var2 是value 当前的值 5 ,var 4是准备要加 1

var4 是当前准备从内存去取得最新的 AtomicInteger 的 value值,

然后进入 compareAndSwapInt 方法 ,这就是我们说的 CAS了

var2是 预期的值 ,var5 是主存中的值, var5+var4是要更新的结果,

当且只当 var2与v5相等时,才会返回更新的结果值。

因为v2的值是当前线程中工作内存的值,只有确认自己读到的值跟主存中的值一致的时候,才能去修改这个值。

在多线程竞争的情况下,如果var2主存中的值 被其它线程修改成3了,

那var2 等于2 的时候 就不等于 主存中的3 ,那么就不会进行相加。

但是使用Atomic这个类 会有一个ABA的问题。

CAS需要检查操作值有没有发生改变,如果没有发生改变则更新。但是存在这样一种情况:如果一个值原来是A,变成了B,然后又变成了A,那么在CAS检查的时候会发现没有改变,但是实质上它已经发生了改变,这就是所谓的ABA问题。对于ABA问题其解决方案是加上版本号,即在每个变量都加上一个版本号,每次改变时加1,即A —> B —> A,变成1A —> 2B —> 3A。

如何解决呢?

Java提供了AtomicStampedReference这个类来解决。

AtomicStampedReference通过版本号stamp,从而避免ABA问题。

compareAndSet有四个参数,分别表示:预期引用、更新后的引用、预期标志、更新后的标志

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年07月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档