AtomicLong原理
  就像我们所知道的那样,AtomicLong的原理是依靠底层的cas来保障原子性的更新数据,在要添加或者减少的时候,会使用死循环不断地cas到特定的值,从而达到更新数据的目的。那么LongAdder又是使用到了什么原理?难道有比cas更加快速的方式?
LongAdder原理
这里让我困惑的一个问题是LongAdder中没有类似于AtomicLong中getAndIncrement()或者incrementAndGet()这样的原子操作,所以只能通过increment()方法和longValue()方法的组合来实现更新和获取的动作,然而这样不能保证这个组合操作的原子性,猜想也许LongAdder就是不具备这样的机制吧。那么就主要看一下increment()和longValue()方法。
increment方法:
分析increment()方法,可以看到该方法就是对add(long x)的封装,那么具体来分析一下这个方法

public void add(long x) {Cell[] as; long b, v; int m; Cell a;if ((as = cells) != null || !casBase(b = base, b + x)) {boolean uncontended = true;if (as == null || (m = as.length - 1) < 0 ||(a = as[getProbe() & m]) == null ||!(uncontended = a.cas(v = a.value, v + x)))longAccumulate(x, null, uncontended);}}

这里重点是casBase(b = base, b + x),来看一下它做了什么

  final boolean casBase(long cmp, long val) {return UNSAFE.compareAndSwapLong(this, BASE, cmp, val);}

这里的四个条件其实并不是并列的,而是递进式的,1和2判断cells数组是否为空,3取cells数组中的任意一个元素a判断是否为空,4是对a进行cas操作并将执行结果赋值标志位uncontended。从这里可以给出第二个结论,当竞争激烈到一定程度无法对base进行累加操作时,会对cells数组中某个元素进行更新。
最后来看一下当上述条件无法全部满足时调用的longAccumulate(x, null, uncontended)方法

final void longAccumulate(long x, LongBinaryOperator fn,boolean wasUncontended) {int h;if ((h = getProbe()) == 0) {ThreadLocalRandom.current(); // force initializationh = getProbe();  //返回当前线程的threadLocalRandomProbe值wasUncontended = true;}boolean collide = false;                // True if last slot nonemptyfor (;;) {Cell[] as; Cell a; int n; long v;if ((as = cells) != null && (n = as.length) > 0) {if ((a = as[(n - 1) & h]) == null) {if (cellsBusy == 0) {       // cells数组中对应位置没有数据则插入新对象Cell r = new Cell(x);   if (cellsBusy == 0 && casCellsBusy()) {boolean created = false;try {               // Recheck under lockCell[] rs; int m, j;if ((rs = cells) != null &&(m = rs.length) > 0 &&rs[j = (m - 1) & h] == null) {rs[j] = r;created = true;}} finally {cellsBusy = 0;}if (created)break;continue;           // Slot is now non-empty}}collide = false;}else if (!wasUncontended)       // CAS already known to failwasUncontended = true;      // Continue after rehashelse if (a.cas(v = a.value, ((fn == null) ? v + x :fn.applyAsLong(v, x))))         //对该位置的cell元素进行累加break;else if (n >= NCPU || cells != as)collide = false;            // At max size or stale   //判断数组大小是否大于核数else if (!collide)collide = true;else if (cellsBusy == 0 && casCellsBusy()) {         //对cells数组进行扩容,直接扩容为2倍try {if (cells == as) {      // Expand table unless staleCell[] rs = new Cell[n << 1];for (int i = 0; i < n; ++i)rs[i] = as[i];cells = rs;}} finally {cellsBusy = 0;}collide = false;continue;                   // Retry with expanded table}h = advanceProbe(h);}else if (cellsBusy == 0 && cells == as && casCellsBusy()) {  //cellsBusy这里是做为一个自旋锁来使用的boolean init = false;try {                           // 初始化cells数组大小为2if (cells == as) {Cell[] rs = new Cell[2];rs[h & 1] = new Cell(x);cells = rs;init = true;}} finally {cellsBusy = 0;}if (init)break;}else if (casBase(v = base, ((fn == null) ? v + x :fn.applyAsLong(v, x))))      //对base进行CAS操作break;                          // Fall back on using base}}

这个方法比较长,大致对几个关键点做了注释,该方法主要是用一个死循环对cells数组中的元素进行操作,当要更新的位置的元素为空时插入新的cell元素,否则在该位置进行CAS的累加操作,如果CAS操作失败并且数组大小没有超过核数就扩容cells数组。

总结
LongAdder类与AtomicLong类的区别在于高并发时前者将对单一变量的CAS操作分散为对数组cells中多个元素的CAS操作,取值时进行求和;而在并发较低时仅对base变量进行CAS操作,与AtomicLong类原理相同。不得不说这种分布式的设计还是很巧妙的。

LongAdder及AtomicLong相关推荐

  1. 性能优化之使用LongAdder替换AtomicLong

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://juejin.cn/post/6921595303460241415 写在前面 本篇文章并不会直接进入主题讲为 ...

  2. [JDK8]性能优化之使用LongAdder替换AtomicLong

    如果让你实现一个计数器,有点经验的同学可以很快的想到使用AtomicInteger或者AtomicLong进行简单的封装. 因为计数器操作涉及到内存的可见性和线程之间的竞争,而Atomic***的实现 ...

  3. Java中的LongAdder和AtomicLong有什么区别?

    ● Java中的LongAdder和AtomicLong有什么区别? 考点:JDK 参考回答: JDK1.8引入了LongAdder类.CAS机制就是,在一个死循环内,不断尝试修改目标值,直到修改成功 ...

  4. LongAdder和AtomicLong哪个性能更好,为什么?

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/limenghua9112/ article/details/107950744 概述 AtomicLong是作者Doug Le ...

  5. 【078期】java.util.* 并发包下 LongAdder 和 AtomicLong 哪个性能更好,为什么?

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方留言必回,有问必答! 每天 08:00 更新文章,每天进步一点点... 概述 ...

  6. LongAdder和AtomicLong

    LongAdder AmoticLong AtomicLong是作用是对长整形进行原子操作. 原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束. 在32位操作系统中,64位 ...

  7. LongAdder 和 AtomicLong

    有幸看到一篇关于这个讲解 2个类的讲解,自己也归纳总结一下. 一.解析 看源码底层会发现实现机制不一样,当然这个也是必须的 LongAdder 点进去之后会发现,CAS 它是一个CAS的实现类.至于C ...

  8. AtomicLong和LongAdder的区别

    转载自 https://blog.csdn.net/yao123long/article/details/63683991 前言   最近在看到不少框架里面使用到了LongAdder这个类,而并非At ...

  9. 线程安全之原子性Atomic(AtomicInteger|LongAdder|AtomicLong)

    线程安全性 当多线程访问某个类时,不管运行环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何的同步或者协同,这个类都能表现出正确的行为,那么这个类就是线程安全的. 原子性 提供 ...

最新文章

  1. html滑动逐渐覆盖效果,创意jQuery和CSS3滑动覆盖响应式幻灯片特效
  2. 从零开始一起学习SLAM | 为啥需要李群与李代数?
  3. Spring - 同一个类中的方法互相调用,注解失效问题的分析和解决(转)
  4. Hadoop教程(三):HDFS、MapReduce、程序入门实践
  5. vue - blog开发学习6
  6. 无线路由器和计算机怎么连接网络连接,华为无线路由器怎么连接宽带上网
  7. python输出日期语句_如何从Python的原始语句中提取时间-日期-时间段信息
  8. NO4 findmv--特殊符号..和.
  9. 长城汽车:魏牌宣布涨价 咖啡系部分车型上调5000-12000元
  10. python海龟作图不用循环_10分钟,利用聪明的小海龟可以制作出绚丽的视觉效果,你信不信呢...
  11. java 云 代码_我 - java代码库 - 云代码
  12. 推荐几款连字字体,在代码编辑器中启用连字字体(Visual Studio Code)
  13. 程序猿财务自由之路·规划篇
  14. windows11修改开机密码为空解决方案
  15. 移动医疗是什么 移动医疗应用实例
  16. LQ0141 纸张尺寸【水题】
  17. 韩顺平-linux笔记
  18. 马云唱京剧《空城计》,柳传志说相声:“商界春晚”大佬们真会玩(附视频)...
  19. 怎样让chatGPT给你打工然后月入过千?
  20. Orcale语句大全

热门文章

  1. python错误2503_Win10卸载python总是提示error2503失败各种解决办法
  2. 2022灵活用工十大新趋势!
  3. php操作redis(list)队列操作
  4. 手机租赁是风口吗?这家公司试推期间日单249
  5. 一个Python写的视频剪辑软件,好用!
  6. 什么是Mobsync.exe,为什么运行?
  7. mysql数据库连表查询的几种方法
  8. 安卓手机卡顿怎么解决_安卓手机卡顿的问题,终于解决了
  9. (2021-07-14~)“kuangbin带你飞”专题计划——专题十三:基础计算几何
  10. ssh中前后台的数据交互