网站引用优酷,oa软件定制开发,柳州 网站开发,南阳网站推广效果前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。点击跳转到教程。
LongAdder是java8中新增的原子类#xff0c;在多线程环境中#xff0c;它比AtomicLong性能要高出不少#xff0c;特别是写多的场景。…
前些天发现了一个巨牛的人工智能学习网站通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到教程。
LongAdder是java8中新增的原子类在多线程环境中它比AtomicLong性能要高出不少特别是写多的场景。
它是怎么实现的呢让我们一起来学习吧。
原理
LongAdder的原理是在最初无竞争时只更新base的值当有多线程竞争时通过分段的思想让不同的线程更新不同的段最后把这些段相加就得到了完整的LongAdder存储的值。 源码分析
LongAdder继承自Striped64抽象类Striped64中定义了Cell内部类和各重要属性。
主要内部类
Cell类使用sun.misc.Contended注解说明是要避免伪共享的。
使用Unsafe的CAS更新value的值其中value的值使用volatile修饰保证可见性。
关于Unsafe的介绍请查看【死磕 java魔法类之Unsafe解析】。
关于伪共享的介绍请查看【杂谈 什么是伪共享false sharing】。
主要属性 最初无竞争或有其它线程在创建cells数组时使用base更新值有过竞争时使用cells更新值。最初无竞争是指一开始没有线程之间的竞争但也有可能是多线程在操作只是这些线程没有同时去更新base的值。
有过竞争是指只要出现过竞争不管后面有没有竞争都使用cells更新值规则是不同的线程hash到不同的cell上去更新减少竞争。
add(x)方法
add(x)方法是LongAdder的主要方法使用它可以使LongAdder中存储的值增加xx可为正可为负。 1最初无竞争时只更新base
2直到更新base失败时创建cells数组
3当多个线程竞争同一个Cell比较激烈时可能要扩容
sum()方法 sum()方法
可以看到sum()方法是把base和所有段的值相加得到那么这里有一个问题如果前面已经累加到sum上的Cell的value有修改不是就没法计算到了么
答案确实如此所以LongAdder可以说不是强一致性的它是最终一致性的。
LongAdder VS AtomicLong
当只有一个线程的时候AtomicLong反而性能更高随着线程越来越多AtomicLong的性能急剧下降而LongAdder的性能影响很小。
总结
1LongAdder通过base和cells数组来存储值
2不同的线程会hash到不同的cell上去更新减少了竞争
3LongAdder的性能非常高最终会达到一种无竞争的状态
彩蛋
在longAccumulate()方法中有个条件是 nNCPU就不会走到扩容逻辑了而n是2的倍数那是不是代表cells数组最大只能达到大于等于NCPU的最小2次方
答案是明确的。因为同一个CPU核心同时只会运行一个线程而更新失败了说明有两个不同的核心更新了同一个Cell这时会重新设置更新失败的那个线程的probe值这样下一次它所在的Cell很大概率会发生改变如果运行的时间足够长最终会出现同一个核心的所有线程都会hash到同一个Cell大概率但不一定全在一个Cell上上去更新所以这里cells数组中长度并不需要太长达到CPU核心数足够了。
比如笔者的电脑是8核的所以这里cells的数组最大只会到8达到8就不会扩容了。