CAS算法

概述

CAS的全程是:Compare And Swap(比较并交换),CAS是实现并发计算时常用到的技术,Java并发包中的很多类都使用了CAS技术,如ConcurrentHashMap,AtomicInteger原子操作等

CAS操作涉及到3个操作符:当前内存中的值、预估值、即将修改的新增,当且仅当预估值等于内存中的值的时候,才将新的值保存到内存中,否则什么都不做


作用

CAS可以将比较和交换转换为原子操作,这个原子操作直接由CPU保证,CAS可以保证共享变量赋值时的原子操作


特点

CAS是一种非阻塞算法的实现,它能在不使用锁的情况下实现多线程安全,所以CAS也是一种无锁算法

一个线程失败或挂起并不会导致其他线程也失败或挂起


案例

AtomicInteger的incrementAndGet()源码

  • AtomicInteger底层使用到了Unsafe类,它提供了原子操作,Unsafe类可以直接操作内存空间的值
  • Unsafe的CompareAndSwapInt()方法其实就是CAS方法,它会自旋判断当前内存中的值与预期的值是否相等,如果相等就会把内存中的值用更新值替换,如果不相等则不操作,以此来保证原子性
  • 基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,也就是说CAS靠硬件实现,从而在硬件层面提升效率

优点

  1. 由于CAS是非阻塞的,可以避免优先级倒置和死锁等问题
  2. 性能好,使用无锁的方式,没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销

缺点

  1. 循环时间长开销大(自旋)

    • 如果CAS失败,会一直进行尝试,如果CAS长时间一直不成功,可能给CPU带来很大的开销
    • 解决方法:破坏调死循环,当超过一定时间或者一定次数时,return退出
  2. 只能保证一个共享变量的原子操作

    • 当对一个共享变量操作时,可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性
    • 解决方法:
      1. 用锁来保证原子性
      2. 把多个共享变量合成一个共享变量来操作
      3. 封装成对象 ;Java1.5开始,JDK提供了AtomicReference类来保证引用对象之前的原子性,可以把多个变量放到一个对象里来进行CAS操作
  3. ABA问题

    • 如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说明它的值没有被其他线程改变过吗?

      如果在这段期间它的值曾经被改称了B,然后又改为A,那CAS就会误认为它从来没有被修改过,这就是ABA问题

    • 解决方法:

      1. Java并发包提供了一个带有标记的原子引用类AtomicStampedReference,它可以通过控制变量值的版本来保证CAS的正确性;即在变量前面添加版本号,每次变量更新的时候都把版本号+1,这样变化过程就变成A-B-A变成1A-2B-3A
      2. 增加时间戳
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>