Java并发编程系列之CAS(1)

一. CAS定义

1. CAS:比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令。

2. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。 

3. 这是作为单个原子操作完成的。 

4. 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。 

5. 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成

二. 简单案例演示


 public static void main(String[] args) {

        //主物理内存设置为 3在这里插入代码片
        AtomicInteger atomicInteger = new AtomicInteger(3); //默认是 0

        //main线程打算在工作内存修改值为 2020
        System.out.println(atomicInteger.compareAndSet(3, 2020)+"\t current data: " + atomicInteger.get());
        
        //main线程打算在工作内存修改值为 1024      
        System.out.println(atomicInteger.compareAndSet(3, 1024)+"\t current data: " + atomicInteger.get());
    }

运行结果:
在这里插入图片描述

结果解析

为什么会出现上面的结果呢?
1. 因为compareAndSet(?,?)方法第一个参数代表的是期望值,
这个值负责和主内存也就是我们定义的3比较,如果相同,就返回true,并且把主存的值给交换掉。
所以会在控制台打印第一句话: true	 current data: 2020
2. 因为现在主内存的值已经被更改为2020,
所以3与之比对失败,返回false,输出主内存的值
这就是控制台打印的第二句话:false	 current data: 2020

三. CAS的底层原理

我们可以看一下其底层代码
以atomicInteger.getAndIncrement();方法为例进入底层
进入一层是AtomicInteger类

 	/**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

在下一层是Unsafe类

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;
    }

解析代码

var1 AtomicInteger对象本身
var2 该对象的引用地址
var4 需要变动的数据
var5 通过var1 var2找出的主内存中真实的值用该对象前的值与var5比较;
如果相同,更新var5+var4并且返回true,退出循环。
如果不同,继续循环取值然后再比较,直到更新完成。
var5 = this.getIntVolatile(var1, var2); 相当于从主内存中取出值复制副本到工作内存。
this.compareAndSwapInt(var1, var2, var5, var5 + var4) 相当于是主内存的值与工作内存的值比较,相同,则改变值。

CAS的缺点

  1. 循环时间长,开销大 例如getAndAddInt方法执行,有个do while循环, 如果CAS失败,一直会进行尝试,如果CAS长时间不成功, 可能会给CPU带来很大的开销

  2. 只能保证一个共享变量的原子操作 对多个共享变量操作时,循环CAS就无法保证操作的原子性, 这个时候,就可以用锁来保证原子性

  3. 可能会引发ABA问题

说明:

ABA:如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化。关于ABA问题我想了一个例子:在你非常渴的情况下你发现一个盛满水的杯子,你一饮而尽。之后再给杯子里重新倒满水。然后你离开,当杯子的真正主人回来时看到杯子还是盛满水,他当然不知道是否被人喝完重新倒满。解决这个问题的方案的一个策略是每一次倒水假设有一个自动记录仪记录下,这样主人回来就可以分辨在她离开后是否发生过重新倒满的情况。这也是解决ABA问题目前采用的策略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值