CAS与Atomic类

CAS

什么是CAS?

CAS全称Compare and swap(比较与替换), 该技术用于并发更新一个值数据时,使用不加锁的方式去安全的更新,

因为加锁是一种比较昂贵的操作,不加锁又无法保证多线程下的安全性,CAS在赋值时,有三个关键值,

  1. 预期值
  2. 新值
  3. 旧值

该操作的原子性由操作系统保证,在赋值时,使用预期值旧值对比,当这两个值相等时,才将内存中的值替换为新值,否则就失败(和乐观锁同理, 也就可以理解CAS就是一种乐观锁),

失败后,通过一个循环的方式(称之为自旋),重新去尝试赋值,直到成功为止,这就是CAS的核心概念了,Java中的Atomic开头相关的类,都是用CAS去做的, 可以在并发情况下提高很大的性能,

下图是Unsafe类的getAndAddInt方法,var1是一个java对象, var2是java对象中某field的偏移量var4想要增加的数 , var5是内存中的值,

使用var1 + var2 获得到内存中的值,也就是var5(预期值), 随后用 var5 + var4 累加出来新值

最终使用本地原子性方法compareAndSwapInt, 使用var5(预期值)var1 + var2(内存值)对比,如果成功, 就将var5 + var4(新值)放入到内存中替换,

否则不停的循环尝试以上步骤:

image.png

因为加锁是一种比较昂贵的操作(类似悲观锁),所以在多线程环境下的共享变量建议都使用对应的Atomic类去做处理(类似乐观锁),

例如 Integer使用AtomicInteger, Boolean使用AtomicBoolean,Long使用AtomicLong

Atomic另一种用途

Atomic除了可以在并发环境下提高性能外,还有另外一种用途, 来看一下下面的Demo,

可以看到在下图中,我们在new Thread外面创建了一个变量counter, 在线程内部对该变量进行累加重新赋值的操作,

但是编译器告诉我们无法操作外部的counter, 原因是因为,我们虽然看起来在新的线程中引用了外面的counter变量,但其实运行时,JVM将外部的counter变量拷贝了一份到新线程的方法栈中,这时候两个counter已经没有什么关系了,

JVM为了防止开发者误以为在线程中可以直接改变外部变量的值,所以限制了这种操作。

image.png

但是再思考一下,仅仅是因为防止开发者误以为可以直接改变外部变量的值,才做的相应的处理的吗?

我们知道线程栈桢中的变量是私有的,只有在当前方法栈中才可以使用,当前方法栈一旦销毁,内部的变量也会被销毁,

如果允许其他的线程修改当前方法栈中的变量,那就颠覆了java对方法栈中局部变量的规定,颠覆了线程模型,所以这个其实还是因为java的线程模型限制的,

推荐文章: https://zhuanlan.zhihu.com/p/82921974 。

java不允许我们在另一个线程中修改一个方法栈中的局部变量,但是如果我们恰巧就是需要修改,这时候就可以采用Atomic类了,看下方代码:

image.png

使用AtomicInteger对象,因为我们改变的是对象中的属性value值,而不是直接修改了局部变量counter的值,

这是被允许的,这就是Atomic除了提升并发性能外的另一种用途。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值