Administrator
Published on 2021-12-15 / 136 Visits
0
0

JUC之原子操作类

JUC之原子操作类

基本类型原子类

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong
//获取当前的值
public final int get() 
//获取当前的值,并设置新的值    
public final int getAndSet(int newValue)
//获取当前的值,并自增    
public final int getAndIncrement()
//获取当前的值,并自减    
public final int getAndDecrement()    
//获取当前的值,并加上预期的值
public final int getAndAdd(int delta)
//如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)       
boolean compareAndSet(int expect, int update)

数组类型原子类

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

引用类型原子类

  • AtomicReference
  • AtomicStampedReference
  • AtomicMarkableReference
    • 它的定义就是将状态戳简化为true|false

对象属性原子类

  • AtomicIntegerFieldUpdater
    • 原子更新对象中int类型字段的值
  • AtomicLongFieldUpdater
    • 原子更新对象中Long类型字段的值
  • AtomicReferenceFieldUpdater
    • 原子更新引用类型字段的值

目的

以一种线程安全的方式操作非线程安全对象内的某些字段

要求

更新的对象属性必须使用 public volatile 修饰符

因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法 newUpdater() 创建一个更新器,并且需要设置想要更新的类和属性

原子操作增强类

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

LongAdder为什么这么快

Striped64

LongAdder是Striped64的子类

Striped64重要的的成员函数

/** CPU数量,即cells数组的最大长度 */
static final int NCPU = Runtime.getRuntime().availableProcessors();

/** cells数组,为2的幂,2,4,8,16.....,方便以后位运算 */
transient volatile Cell[] cells;

/**基础value值,当并发较低时,只累加该值主要用于没有竞争的情况,通过CAS更新 */
transient volatile long base;

/**创建或者扩容Cells数组时使用的自旋锁变量调整单元格大小(扩容),创建单元格时使用的锁*/
transient volatile int cellsBusy;

LongAdder的基本思路就是分散热点,将value值分散到一个Cell数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回

sum()会将所有Cell数组中的value和base累加作为返回值,核心的思想就是将之前AtomicLong一个value的更新压力分散到多个value中去,从而降级更新热点

LongAdder在无竞争的情况,跟AtomicLong一样,对同一个base进行操作,当出现竞争关系时则是采用化整为零的做法,从空间换时间,用一个数组cells,将一个value拆分进这个数组cells

多个线程需要同时对value进行操作时候,可以对线程id进行hash得到hash值,再根据hash值映射到这个数组cells的某个下标,再对该下标所对应的值进行自增操作。当所有线程操作完毕,将数组cells的所有值和无竞争值base都加起来作为最终结果

longAdder.increment() 过程

  • add 方法

    • 最初无竞争时只更新 base
    • 如果更新 base 失败后,首次新建一个Cell 数组
    • 当多个线程竞争同一个 Cell 比较激烈时,可能就要对 Cell 扩容
  • longAccumulate 方法

  • sum 方法

    • sum()会将所有 Cell 数组中的 value 和 base 累加作为返回值

Comment