CAS操作

什么是CAS?

CAS:Compare And Swap,即比较再交换。是 JDK 提供的非阻塞原子性操作,他通过硬件保证了比较——更新操作的原子性。JDK 里面的 Unsafe 类提供了一系列的 compareAndSwap* 方法。

CAS 算法理解

  1. 与锁相比,使用比较交换会使程序看起来更加复杂一些。但由于其非阻塞性,它对死锁问题天生免疫,并且线程间的相互影响也远远比基于锁的方式要小。更为重要的是,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,因此,它要比基于锁的方式拥有更优越的性能。
    简单来说就是,无锁的好处:在高并发的情况下,它比有锁拥有更好的性能。天生就是死锁免疫的。
  2. CAS 操作是抱着乐观的态度进行的,它总是认为自己可以成功完成操作。当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会呗挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理,CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。
  3. 简单地说,CAS 需要你额外给出一个期望值,也就是你认为这个变量线程应该是什么样子的。如果变量不是你想象得那样,那说明他已经被别人修改过了。你就重新读取,再次尝试修改就好了。
  4. 在硬件层面,大部分现代处理器都已经支持原子化的 CAS 指令。在 JDK5.0 以后,虚拟机便可以使用这个指令来实现并发操作和并发数据结构,并且,这种操作在虚拟机中可以说是无处不在。
算法过程:

以 boolean compareAndSwapLong(Object obj, long valueOffset, long except, long update)方法为例:
其中 compareAndSwap 的意思是比较并交换。CAS 有四个操作数:对象内存的位置、对象中的变量的偏移值、变量预期值和新的值。如果对象 obj中内存偏移量为 valueOffset 的变量值为 except,则使用新的值update 替换旧的值 expect。这是处理器提供的一个原子性的命令。
简单的说,valueOffset 表示要更新的变量,except 表示预期值,update 表示新值。只有当 valueOffset=except 时,才会将 valueOffset 的值设为 update,如果 valueOffset!=except,则说明已经有其他线程做了更新操作,则当前线程什么都不做。

CAS 操作的 ABA 问题

假如线程 1 使用 CAS 修改初始值为 A 的变量 X,那么线程 1 会首先去获取当前变量 X 的值(为 A ),然后使用 CAS 操作尝试修改 X 的值为 B,如果使用 CAS 操作成功了,那么程序运行一定是正确的吗?其实未必,这是因为有可能线程 1 获取变量 X 的值为 A 后,在执行 CAS 之前,线程 2 使用 CAS 修改了变量 X 的值为 B,然后又使用 CAS 修改了变量 X 的值为 A。所以虽然线程 1 执行 CAS 时 X 的值是 A,但是这个 A 已经不是线程 1 获取时的 A 了。这就是 ABA 问题。

ABA 问题的产生时因为变量的状态值产生了环形转换,就是变量的值可以从 A 到 B,然后再从 B 到 A。如果变量的值只能朝着一个方向转换,比如 A 到 B,B 到 C,不构成环形,就不会存在问题。JDK 中的 AtomicStampedReference 类给每个变量的状态值都配备了一个时间戳,从而避免了 ABA 问题的产生。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值