1. 对CAS了解多少
    • CAS的全称为compare and swap,比较并交换。是一个原子性的操作,对应到CPU指令为cmpxchg
    • CAS的操作其实非常简单。
      • CAS 有三个操作数:当前值 A、内存值 V、要修改的新值 B
      • 假设 当前值A 跟 内存值V 相等,那就将 内存值V 改成B
      • 假设 当前值A 跟 内存值V 不相等,要么就重试,要么就放弃更新
      • 将当前值与内存值进行对比,判断是否有被修改过,这就是CAS的核心
      • image.png
    1. 为什么要用CAS
    • synchronized 锁每次只会让一个线程去操作共享资源
    • CAS 相当于没有加锁,多个线程都可以直接操作共享资源,在实际去修改的时候才去判断能否修改成功,很多的情况下会synchronized锁要高效很多
    • 对一个值进行累加,就没必要使用 synchronized 锁,使用 juc 包下的 Atomic 类就足以
    1. CAS会有什么缺点
    • 会带来ABA的问题
    • 从CAS更新的时候,我们可以发现它只比对当前值和内存值是否相等,这会带来个问题
      • 假设线程A读到当前值是10,可能线程B把值修改为100,然后线程C又把值修改为10。
      • 等到线程A拿到执行权时,因为当前值和内存值是一致的,线程A是可以修改的!
      • 站在线程A的角度来说,这个值是从未被修改的(:
      • 这是不合理的,因为我们从上帝的角度来看,这个变量已经被线程B和线程C修改过了。
      • 这就是所谓的ABA问题
      • CAS - 图2
    • 要解决 ABA 的问题,Java也提供了 AtomicStampedReference 类供我们用,说白了就是加了个版本,比对的就是内存值+版本是否一致
    1. 阿里巴巴开发手册提及到 推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)
    • AtomicLong 做累加的时候实际上就是多个线程操作同一个目标资源
    • 在高并发时,只有一个线程是执行成功的,其他的线程都会失败,不断自旋(重试),自旋会成为瓶颈
    • 而LongAdder的思想就是把要操作的目标资源「分散」到数组Cell中
    • 每个线程对自己的 Cell 变量的 value 进行原子操作,大大降低了失败的次数
    • 这就是为什么在高并发场景下,推荐使用LongAdder 的原因(: