Java并发-CAS & Atomic


  • CAS
  • Atomic
  • LongAdder

  • CAS(Compare And Swap,比较并交换):针对一个变量,首先比较它的内存值与某个期望值是否相同,如果相同,就给它赋一个新值
    • 一个不可分割的原子操作,并且其原子性是直接在硬件层面得到保障的
  • CAS缺陷
    • 自旋 CAS 长时间地不成功,则会给 CPU 带来非常大的开销
    • 只能保证一个共享变量原子操作
    • ABA 问题
      • 加时间戳的原子操作类(AtomicStampedReference<V>)
      • AtomicMarkableReference(只关心是否修改过,而不关心修改次数)

  • java.util.concurrent.atomic
    • 基本类型:AtomicInteger、AtomicLong、AtomicBoolean
    • 引用类型:AtomicReference、AtomicStampedRerence、AtomicMarkableReference
    • 数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
    • 对象属性原子修改器:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
      • 字段必须是volatile类型的
      • 调用者能够直接操作对象字段(修饰符public/protected/default/private),但是子类是不能操作父类的字段,尽管子类可以访问父类的字段
      • 只能是实例变量,不能是类变量,也就是说不能加static关键字
      • 只能是可修改变量,不能使final变量,因为final的语义就是不可修改(实际上volatile和final的语义本来就是冲突的)
      • 不能修改其包装类型,如果要修改包装类型就需要使用AtomicReferenceFieldUpdater
    • 原子类型累加器(jdk1.8增加的类):DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

  • LongAdder解决高并发环境下AtomicLong的自旋瓶颈问题:尽量减少热点冲突,不到最后万不得已,尽量将CAS操作延迟
    • 基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作
    • 如果要获取真正的long值,只要将各个槽中的变量值累加返回
  • LongAdder的内部结构:一个base变量,一个Cell[]数组
    • base变量:非竞态条件下,直接累加到该变量上
    • Cell[]数组:竞态条件下,累加到各个线程自己的槽Cell[i]中
  • LongAdder#add
    • CPU核数,用来决定槽数组的大小,大小为2的次幂
    • 没有遇到并发竞争时,直接使用base累加数值
      • 只有从未出现过并发冲突的时候,base基数才会使用到,一旦出现了并发冲突,之后所有的操作都只针对Cell[]数组中的单元Cell
    • 初始化cells数组时,必须要保证cells数组只能被初始化一次(即只有一个线程能对cells初始化),他竞争失败的线程会讲数值累加到base上
      • 如果Cell[]数组未初始化,会调用父类的longAccumelate去初始化Cell[],如果Cell[]已经初始化但是冲突发生在Cell单元内,则也调用父类的longAccumelate,此时可能就需要对Cell[]扩容了
    • 累加到各个线程自己的槽Cell[i]中
  • Striped64#longAccumulate
  • LongAdder#sum:返回累加的和,也就是"当前时刻"的计数值(计算总和时没有对Cell数组进行加锁)
    • 高并发时,除非全局加锁,否则得不到程序运行中某个时刻绝对准确的值
    • 此返回值可能不是绝对准确的,因为调用这个方法时还有其他线程可能正在进行计数累加,方法的返回时刻和调用时刻不是同一个点,在有并发的情况下,这个值只是近似准确的计数值
  • LongAccumulator是LongAdder的增强版:提供了自定义的函数操作(LongBinaryOperator)
    • 内部原理和LongAdder几乎完全一样,都是利用了父类Striped64的longAccumulate方法

文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录