如果让你实现一个计数器,有点经验的同学可以很快的想到使用AtomicInteger或者AtomicLong进行简单的封装。

因为计数器操作涉及到内存的可见性和线程之间的竞争,而Atomic***的实现完美的屏蔽了这些技术细节,我们只需要执行相应的方法,就能实现对应的业务需求。

Atomic**虽然好用,不过这些的操作在并发量很大的情况下,性能问题也会被相应的放大。我们可以先看下其中getAndIncrement的实现代码

public final long getAndIncrement() {return unsafe.getAndAddLong(this, valueOffset, 1L);
}// unsafe类中的实现
public final long getAndAddLong(Object var1, long var2, long var4) {long var6;do {var6 = this.getLongVolatile(var1, var2);} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));return var6;
}

很显然,在getAndAddLong实现中,为了实现正确的累加操作,如果并发量很大的话,cpu会花费大量的时间在试错上面,相当于一个spin(自旋)的操作。如果并发量小的情况,这些消耗可以忽略不计。

既然已经意识到Atomic***有这样的业务缺陷,Doug Lea大神又给我们提供了LongAdder,内部的实现有点类似ConcurrentHashMap的分段锁,最好的情况下,每个线程都有独立的计数器,这样可以大量减少并发操作。

下面通过JMH比较一下AtomicLong 和 LongAdder的性能。

@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.Throughput)
public class Main {private static AtomicLong count = new AtomicLong();private static LongAdder longAdder = new LongAdder();public static void main(String[] args) throws Exception {Options options = new OptionsBuilder().include(Main.class.getName()).forks(1).build();new Runner(options).run();}@Benchmark@Threads(10)public void run0(){count.getAndIncrement();}@Benchmark@Threads(10)public void run1(){longAdder.increment();}
}

1、设置BenchmarkMode为Mode.Throughput,测试吞吐量
2、设置BenchmarkMode为Mode.AverageTime,测试平均耗时

线程数为1

1、吞吐量

Benchmark   Mode  Cnt    Score   Error   Units
Main.run0  thrpt    5  154.525 ± 9.767  ops/us
Main.run1  thrpt    5   89.599 ± 7.951  ops/us

2、平均耗时

Benchmark  Mode  Cnt  Score    Error  Units
Main.run0  avgt    5  0.007 ±  0.001  us/op
Main.run1  avgt    5  0.011 ±  0.001  us/op

单线程情况:
1、AtomicLong的吞吐量和平均耗时都占优势

线程数为10

1、吞吐量

Benchmark   Mode  Cnt    Score     Error   Units
Main.run0  thrpt    5   37.780 ±   1.891  ops/us
Main.run1  thrpt    5  464.927 ± 143.207  ops/us

2、平均耗时

Benchmark  Mode  Cnt  Score   Error  Units
Main.run0  avgt    5  0.290 ± 0.038  us/op
Main.run1  avgt    5  0.021 ± 0.001  us/op

并发线程为10个时:

  • LongAdder的吞吐量比较大,是AtomicLong的10倍多。
  • LongAdder的平均耗时是AtomicLong的十分之一。

线程数为30

1、吞吐量

Benchmark   Mode  Cnt    Score    Error   Units
Main.run0  thrpt    5   36.215 ±  2.341  ops/us
Main.run1  thrpt    5  486.630 ± 26.894  ops/us

2、平均耗时

Benchmark  Mode  Cnt  Score   Error  Units
Main.run0  avgt    5  0.792 ± 0.021  us/op
Main.run1  avgt    5  0.063 ± 0.002  us/op

线程数为30个时:

  • LongAdder的吞吐量比较大,也是AtomicLong的10倍多。
  • LongAdder的平均耗时也是AtomicLong的十分之一。

总结

一些高并发的场景,比如限流计数器,建议使用LongAdder替换AtomicLong,性能可以提升不少。

转载于:https://www.cnblogs.com/Joy-Hu/p/10715682.html

[JDK8]性能优化之使用LongAdder替换AtomicLong相关推荐

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

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

  2. 拉勾教育 | Java 性能优化实战 21 讲

    开篇词 开篇词 | Java 性能优化,是进阶高级架构师的炼金石 你好,我是李国.作为<Java 性能优化与面试 21 讲>这个课程的作者,我先来简单介绍下自己. 我曾任京东金融.陌陌科技 ...

  3. 《C++性能优化指南》 linux版代码及原理解读 第四章

    目录 概述 为什么字符串很麻烦 字符串是动态分配的 字符串赋值背后的操作 如何面对字符串会进行大量复制 写时复制COW(copy on write) 尝试优化字符串 避免临时字符串 通过预留存储空间减 ...

  4. webpack学习:性能优化

    本文内容如下 性能优化相关内容 如果你都有了答案,可以忽略本文章,或去webpack学习导图寻找更多答案 性能优化两大方面 一,开发环境性能优化 优化: 构建速度,代码调试 HMR热模块更新(代码调试 ...

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

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

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

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

  7. 【Webpack 性能优化系列(1) - HMR 热模块替换】

    webpack系列文章: [Webpack 性能优化系列(9) - 多进程打包]极大的提升项目打包构建速度!!! [Webpack 性能优化系列(8) - PWA]使用渐进式网络应用程序为我们的项目添 ...

  8. 性能优化常用工具及经验总结

    文 |齐光 性能问题和 Bug 不同,后者的分析和解决思路更清晰,很多时候从应用日志(文中的应用指分布式服务下的单个节点)即可直接找到问题根源,而性能问题,其排查思路更为复杂一些. 对应用进行性能优化 ...

  9. 《Java性能调优实战》笔记(一)Java编程性能调优、多线程性能优化

    文章目录 一.Java性能调优概述 1.1 性能调优标准 1.2 制定性能调优策略 二.Java编程性能调优 2.1 字符串 2.2 正则表达式 2.3 ArrayList和LinkedList的选择 ...

最新文章

  1. 什么是SESSION?(二)
  2. MyBatis学习总结(14)——Mybatis使用技巧总结
  3. 手把手构建LSTM的向前传播(Building a LSTM step by step)
  4. matlab循环矩阵
  5. 通过rsync清除目录的shell脚本
  6. 夏季防暑降温小常识汇总 - 生活至上,美容至尚!
  7. Redis 集合处理
  8. 《数据结构与算法分析-C语言描述》习题2.6
  9. 生成器案例,#采集日志
  10. [转]数据科学家能力发展路线图
  11. mysql 事务 不同库_MYSQL数据库重点:事务与锁机制
  12. mysql自动判断索引机制_Mysql优化之索引实现原理
  13. matlab求导函数作图,excel对数据求导作图/如何用excel计算导数
  14. Android关于网络访问app应用开发相关的异常总结
  15. 产品发布 | 全程托管、化繁为简,京东云上线API网关服务
  16. Expiring XXX record(s) for XXX:120015 ms has passed since batch creation
  17. 神经网络性能评价指标
  18. ol-ext transform 对象,旋转、拉伸、放大(等比例缩放),事件监听
  19. Swing学习笔记目录
  20. Xxl-Job 初次体验

热门文章

  1. session不是线程安全的
  2. APP压力測试新手教程
  3. C++11中正則表達式測试
  4. 设置修改CentOS系统时区
  5. 艰难万苦配置postfix+ldap+extmail+.......
  6. -9 逆序输出一个整数的各位数字_计算机基础知识: 信息数字化
  7. C 判断 —— if...else 语句(bool变量、float变量、指针变量与“零值”进行比较)(else 到底与哪个 if 配对呢? if 语句后面的分号?)
  8. 构造函数和析构函数的调用过程
  9. ReactNative生成android平台的bundle文件命令
  10. iOS WKWebView ios9以上版本配置 与 设置UserAgent(用户代理), 解决点击web, 客户端接收不到web事件问题...