LongAdder.add(long x)流程
2020-08-22 17:30:43 7 举报
LongAdder.add(int i)方法流程
作者其他创作
大纲/内容
是
自旋开始
break;修改成功,结束自旋
默认uncontended = true;
防止其他线程初始化了,自己当前线程再次初始化,导致丢失数据
判断 init
1.扩容数组(原cell数组长度的2倍大小)2.将新数组指向cells变量
cells == as判断cells数组是否被修改过?⑦
创建对象之前要判断当前锁是否被占用
是,为null就要创建新对象⑤
设置 collide = true;
否
end
true,可以修改
当前线程对应下标的cell元素是否为null
设置为true了后下一次自旋过来有可能就会到达这里,然后走右边的数组扩容
否,更新base失败
如果 collide == false
cells == as判断cells数组是否已被修改了⑦
不是,为true
判断cell数组是否初始化,并且判断当前线程下标所在的cell元素是否为null⑥
设置collide = false;自旋重试;
base是否成功更新?
返回 uncontended = false
cas修改cell的value值
1. 设置cellsBusy = 0 其他线程也可获得锁;2.设置 collide = false 不可扩容;3. continue,自旋重试
1.创建一个大小为2的cells数组,并创建一个cell元素放入数组中,并将当前数组指向cells2.设置init = true3.设置 cellsBusy = 0,释放锁
设置 wasUncontended = true;自旋重试
调用longAccumulate()方法
①有多个线程并发修改base导致发生了并发冲突②并发冲突,有多个线程同时更新当前cell的value值,只有一个能成功,其他都失败,③uncontended 默认为true,为false是因为cells数组已被初始化,当前线程对应下标的cell元素不为null,并且cas更新cell对象中value值失败④cells数组被初始化,那么应该将数据写入到cell中⑤当前线程对应下标的cell元素为null,那么就需要创建它⑥再次判断当前线程对应下标的cell元素是否创建,是为了防止其他线程已创建,自己再初始化,导致丢数据⑦防止其他线程初始化了,自己当前线程再次初始化,导致丢失数据
否,未被修改
是,为flase
自旋,此时cells数组肯定已经被初始化了,
再次判断锁是否被占用并且能否获取到锁
重置当前线程的hash值,再次自旋后会判断当前线程对应的cell元素为null,然后按照流程继续走下去
cells数组已初始化,并且当前cell为null
自旋重试
1.判断锁是否是自由状态2.cells数组是否被修改3.cas修改cellBusy,获取锁
否,更新失败②
wasUncontended:只有cells初始化之后,并且当前线程竞争修改失败,才会是 false
否,未初始化
创建一个Cell对象
是。初始化①
是,获取锁成功
cells数组是否被初始化
文本
是,被占用
获取当前线程的hash值;默认collide = false;
add()
cas替换base值
true
是,长度大于或cells数组已被修改
break结束自旋
否,获取锁失败
判断当前线程对应下标的cell元素是否为 null?
判断如果cells数组长度大于CPU数量或者其他修改已修改过cells数组
获取锁失败
是,更新成功
获取锁成功
collide = false;扩容意向,false:一定不会扩容,true:可能会扩容
1设置新创建cell元素给当前下标2.设置created = true,标识自己创建成功,可以退出自旋3.设置 cellBusy = 0,释放锁标记,让其他线程也能获取锁4.判断 created == true ,break循环,false 则continue
部分注释:
再次判断cells数组是否初始化?
是,更新base成功
判断能否cas更新cell中value的值?
base是否更新成功?
判断 wasUncontended是否为false
当前cells数组是否被初始化
加锁失败,表示其他线程正在初始化数组,此时尝试更新base值
否,数组未初始化
到达真正扩容逻辑
否,未被占用
成功更新,break;end
是,当前cells数组已被初始化④
LongAdder主要是为了优化AtomicInteger的cas自旋操作并发太大时太过耗时而出现的另一种原子操作Integer的类。主要逻辑:LongAdder原子加1首先尝试在base变量上cas方式加1,如果失败则再去 Cell[] 数组中寻找某一个元素,在这个元素上cas方式对 value 变量加1。总体而言,LongAdder的add后所得值就是 base 值加上 所有 Cell[] 数组中所有 value变量值相加。源码参考LongAdder的sum()方法class LongAdder extends Striped64{ public void add(long x) {} public long sum() {}}class Striped64{ // 当cas方式修改base 失败时,此时尝试在 cell[] 数组中找一元素,将值加到这个元素中 transient volatile Cell[] cells; // 没有并发竞争时,数据会累加到base上 or 当 cells 扩容时将数据写到 base 中 transient volatile long base; // 可以当作锁的标记,默认0-可以获取锁,未被占用,1-不能获取锁,已被占用 transient volatile int cellsBusy;}
设置 collide = false; false:表示不再扩容,防止无限制扩容
否,不能修改
判断当前锁是否是自由状态,并且竞争到锁了
0 条评论
下一页