LongAdder源码解析

LongAdder源码解析

大致描述:

当并发较小时,通过cas更新base值即可;

随着并发量增加,cas更新base出现失败的情况,这是开始初始化cells(Cell[]),将增加的值存在cells中;后续对非空的cells位置访问,同样做cas更新操作。当cells数组某些热点位置的并发更新压力过大,会对cells数组进行扩容,分散热点。

最终获取结果为
b a s e + ∑ i = 0 c e l l s . l e n g t h − 1 c e l l s [ i ] base + \sum_{i=0}^{cells.length-1}{cells[i]} base+i=0cells.length1cells[i]

Note

    // CPU核数,Cell数组的长度限制
    NCPU

    // Cell[],不为空时,长度为2^n    
    cells   
	
    // 基础的值    
    base    
    
    // 调整大小和/或创建单元格时使用自旋锁(通过 CAS 锁定)    
    cellsBusy
    
    // 更新cells是否发生冲突    
    uncontended    
  1. 访问量较低时,并发量小,直接cas更新base的值
    image-20220826104252696

  2. 随着并发量的增加,cas更新base的值出现false的情况,此时cells数组还是null进入到longAccumulate方法。

    image-20220826112634832

    cells数组初始化,根据当前线程的hash值,将该次的增量放入到cells数组中(h & (cells.length -1)等价于h % cells.length)

    image-20220826113231397

    双重检测针对的特殊场景:

    线程A进了第一个if判断和第二个if判断,在执行第二个if中对cells引用赋值之前,线程B仅执行过了第一个if的cells == as判断(指令重排),cellsBusy == 0 和 casCellsBusy()暂未执行,若没有双重检查,线程B进入以后,会对cells重新赋值,那么线程A的操作就丢失了。
    
  3. 后续并发线程在base上cas更新失败时,对cells添加值,分为以下两种情况

    1. 向为空的cells位置设置值。

    image-20220828224459724

    进入到longAccumulate方法

    image-20220828224926190

    通过cas获取得到锁,对cells数组对应的位置设置增量

    1. 向已经有值的位置作cas更新操作。

      image-20220828225136534

  4. 后续在高并发下,对cells数组做cas增量的更新时,发生冲突导致cas失败时,uncontended字段置为false,进入longAccumulate方法。

image-20220828225444370
image-20220828225528517

重新获取hash值,向新的cells位置作cas更新操作,根据这次cas操作的结果走向两个不同的分支:

  1. 若这次cas更新操作成功的话,则到此结束(重新hash后,也是可能找到一个空的位置去插入增量,这里以向一个已经有值的cells中的位置做cas更新操作举例)

    image-20220828225926553

  2. 若此次cas更新仍然失败,就要对该cells数组进行扩容了(其实还有一次重hash的机会,后面介绍)

    image-20220828230435586

    扩容后,重复1、2分支的情况(cells数组扩容后,h & (cells.length -1)的值与之前可能不再相同了),成功则结束,失败则继续扩容。

  3. 后续的并发可能还会带来扩容操作,cells数组的长度也不断变大。

    image-20220828232022147

    当cells的长度大于或等于cpu核数以后,再扩容也没有意义了,去重新获取hash值,重新在去做cas。

    上图的第二个分支

    image-20220828232455803

    可以看成一个缓冲,在扩容之前去重hash,再去试一次cas。

执行流程图:

img

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值