Atomic原子操作类详解
2022-11-22 15:14:43 0 举报
Atomic原子操作类详解
作者其他创作
大纲/内容
是
fail
Cell[]是否初始化
出现过并发冲突
Cell[]是否正在初始化?
否
更新成功
直接CAS更新base值
CAS更新base数据成功
LongAdder#add方法
AtomicLong中有个内部变量value保存着实际的long值,所有的操作都是针对该变量进行。也就是说,高并发环境下,value变量其实是一个热点,也就是N个线程竞争一个热点。LongAdder的基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。
LongAdder引入的初衷——解决高并发环境下AtomicInteger,AtomicLong的自旋瓶颈问题。
再次判断Cell[]是否已经初始化
未出现过并发冲突
更新base成功
CAS更新Cell单元成功
Thread3
对于AtomicIntegerFieldUpdater 的使用稍微有一些限制和约束,约束如下:(1)字段必须是volatile类型的,在线程之间共享变量时保证立即可见.eg:volatile int value = 3(2)字段的描述类型(修饰符public/protected/default/private)与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。(3)只能是实例变量,不能是类变量,也就是说不能加static关键字。(4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。(5)对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。
当前线程hash出来映射到Cell的单位是否是null
Cell3
Thread4
调用Striped64#longAccumulate方法
Thread5
CAS更新Cell单元中的数值(根据当前线程的hash数映射到指定的槽位)
再次判断Cell[]是否初始化
end
尝试将当前数值直接累加到base基数
Cell1
cas
操作成功
存在多个线程hash到同一个槽位,并发操作导致CAS失败
初始化Cell[]成功?
尝试加锁并创建Cell单元对象
Thread1
开始进行扩容,Cell[]扩容原来的2倍
尝试加锁,并初始化数组,数组大小为2,然后给当前线程分配一个Cell单元
基本类型:AtomicInteger、AtomicLong、AtomicBoolean;引用类型:AtomicReference、AtomicStampedRerence、AtomicMarkableReference;数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray对象属性原子修改器:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater原子类型累加器(jdk1.8增加的类):DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64
Cell2
base
Striped64#longAccumulate
尝试CAS更新cell单元值
设计思路
Thread2
LongAdder内部有一个base变量,一个Cell[]数组:base变量:非竞态条件下,直接累加到该变量上Cell[]数组:竞态条件下,累加个各个线程自己的槽Cell[i]中
Cell4
开始
是否进行扩容Cell[]大小小于CPU核数时才扩容
0 条评论
回复 删除
下一页