当前位置: 首页 > news >正文

阿里推荐 LongAdder ,不推荐 AtomicLong !

其他系列文章导航

Java基础合集
数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、CAS

1.1 CAS 全称

1.2 通俗理解CAS

1.3 CAS的问题

1.4 解决 ABA 问题

二、LongAdder

2.1 什么是 LongAdder

2.2 为什么推荐推荐 LongAdder

三、AtomicLong

3.1 什么是 AtomicLong 

3.2 为什么不推荐 AtomicLong

四、总结


前言

在分布式系统中,计数器是一个常见的需求。为了实现高并发、高可用的计数器,我们需要选择一个合适的实现方式。

在 Java 中,有两种常见的计数器实现方式:AtomicLong 和 LongAdder。

最近,阿里巴巴在一份技术报告中推荐使用 LongAdder ,而不是 AtomicLong 。

本文将介绍这两种计数器的原理和优缺点,并分析为什么阿里巴巴推荐使用 LongAdder 。


一、CAS

1.1 CAS 全称

全称:compare and swap,比较并交换。
虽然翻译过来是[比较并交换],但它是一个原子性的操作,对应到CPU指令为 cmpxchg 。

1.2 通俗理解CAS

  1. CAS 有三个操作数:当前值A、内存值V、要修改的新值B。
  2. 假设 当前值A 跟 内存值V 相等,那就将内存值V 改成B。
  3. 假设 当前值A 跟 内存值V 不相等,要么就重试,要么就放弃更新。
  4. 将当前值与内存值进行对比,判断是否有被修改过,这就是CAS的核心。

1.3 CAS的问题

CAS有个缺点就是会带来 ABA 的问题。
从CAS更新的时候,我们可以发现它只比对当前值和内存值是否相等,这会带来个问题,下面我举例说明下:

  1. 假设线程A读到当前值是10,可能线程B把值修改为100,然后线程C又把值修改为10。
  2. 等到线程A拿到执行权时,因为当前值和内存值是一致的,线程A是可以修改的!
  3. 站在线程A的角度来说,这个值是从未被修改的 。
  4. 这是不合理的,因为我们从上帝的角度来看,这个变量已经被线程B和线程C修改过了。

1.4 解决 ABA 问题

要解决ABA的问题,Java 也提供了 AtomicStampedReference 类供我们用,说白了就是加了个版本,比对的就是内存值+版本是否一致。

疑问:

为什么阿里巴巴开发手册提及到推荐使用 LongAdder 对象,比AtomicLong 性能更好(减少乐观锁的重试次数)?

原因:

因为 AtomicLong 做累加的时候实际上就是多个线程操作同一个目标资源。

在高并发时,只有一个线程是执行成功的,其他的线程都会失败,不断自旋(重试),自旋会成为瓶颈。

而 LongAdder 的思想就是把要操作的目标资源 分散,到数组 Cell 中。

每个线程对自己的 Cell 变量的 value 进行原子操作,大大降低了失败的次数。

这就是为什么在高并发场景下,推荐使用 LongAdder  的原因。


二、LongAdder

2.1 什么是 LongAdder

LongAdder是JDK1.8由Doug Lea大神新增的原子操作类,位于java.util.concurrent.atomic包下,LongAdder在高并发的场景下会比AtomicLong 具有更好的性能,代价是消耗更多的内存空间

LongAdder是Google开源的一个高性能计数器实现。它采用了一种分段锁的策略,将一个long型的变量分割成多个16字节的段,每个段都使用一个独立的AtomicLong进行更新。这样,在高并发场景下,多个线程可以同时对不同的段进行更新操作,互不干扰。

LongAdder的优点是并发性能高,适用于高并发的场景。由于采用了分段锁的策略,LongAdder可以避免AtomicLong中的竞争问题。此外,LongAdder还支持可扩展性,可以通过增加更多的段来提高性能。但是,LongAdder的缺点是代码相对复杂一些,需要更多的维护成本。

2.2 为什么推荐推荐 LongAdder

LongAdder设计思想上,采用分段的方式降低并发冲突的概率。通过维护一个基准值base和 Cell 数组

如下图所示:


三、AtomicLong

3.1 什么是 AtomicLong 

AtomicLong是Java提供的一个原子类,用于实现高并发的计数器。它利用了CAS(Compare-and-Swap)操作来保证线程安全。在AtomicLong中,每次计数操作都会先读取当前值,然后使用CAS操作更新值。如果值没有被其他线程修改过,则更新成功,否则需要重新尝试。

AtomicLong的优点是简单易用,性能也不错。但是,在高并发场景下,AtomicLong可能会出现竞争问题。因为多个线程可能同时读取和更新同一个AtomicLong的当前值,导致数据不一致。此外,AtomicLong的CAS操作也可能因为硬件和操作系统的原因出现失败的情况。

3.2 为什么不推荐 AtomicLong

在LongAdder之前,当我们在进行计数统计的时,通常会使用AtomicLong来实现。AtomicLong能保证并发情况下计数的准确性,其内部通过CAS来解决并发安全性的问题。

如下图所示:

图里可以看出在高并发情况下,当有大量线程同时去更新一个变量,任意一个时间点只有一个线程能够成功,绝大部分的线程在尝试更新失败后,会通过自旋的方式再次进行尝试,这样严重占用了CPU的时间片,进而导致系统性能问题。


四、总结

阿里巴巴推荐使用LongAdder的原因主要有以下几点:

  1. 高并发性能:LongAdder采用分段锁的策略,可以避免AtomicLong中的竞争问题,提高并发性能。在分布式系统中,高并发性能是非常重要的。
  2. 可扩展性:LongAdder支持可扩展性,可以通过增加更多的段来提高性能。这对于需要处理大量请求的分布式系统来说是非常有利的。
  3. 代码简单易懂:虽然LongAdder的代码相对复杂一些,但是相对于AtomicLong来说更容易理解和维护。这对于开发人员来说是非常重要的。
  4. 更好的适用场景:阿里巴巴推荐使用LongAdder主要是因为在分布式系统中需要一个高性能、高可用的计数器实现。而LongAdder正好符合这个需求。

总之,阿里巴巴推荐使用LongAdder的原因主要是因为它的高并发性能、可扩展性、代码简单易懂以及更好的适用场景。当然,在实际应用中还需要根据具体场景和需求进行选择和优化。


相关文章:

  • Qt使用ffmpeg获取视频文件封面图
  • Idea小技巧
  • 【密码学引论】密码协议
  • 【LeetCode】151. 反转字符串中的单词(StringBuilder类)
  • Amazon CodeWhisperer 在 vscode 的应用
  • 全球移动通信(2G/3G/4G/5G)频谱分布情况
  • 程序员的50大JVM面试问题及答案
  • 【笔记】网络流算法模板
  • CSS3新增样式
  • Gitlab仓库推送到Gitee仓库的一种思路
  • 腾讯云debian服务器的连接与初始化
  • 基于Java (spring-boot)的宠物管理系统
  • 【运维面试100问】(九)了解Raid嘛?
  • 【正点原子STM32连载】第十七章 通用定时器中断实验 摘自【正点原子】APM32E103最小系统板使用指南
  • Mysql的SQL优化和锁
  • 【笔记】你不知道的JS读书笔记——Promise
  • ➹使用webpack配置多页面应用(MPA)
  • 2018一半小结一波
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • ECMAScript6(0):ES6简明参考手册
  • pdf文件如何在线转换为jpg图片
  • python 学习笔记 - Queue Pipes,进程间通讯
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • Spark学习笔记之相关记录
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • uni-app项目数字滚动
  • 自动记录MySQL慢查询快照脚本
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • # Panda3d 碰撞检测系统介绍
  • #Linux(make工具和makefile文件以及makefile语法)
  • #QT(智能家居界面-界面切换)
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (09)Hive——CTE 公共表达式
  • (C#)获取字符编码的类
  • (南京观海微电子)——COF介绍
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十一)c52学习之旅-动态数码管
  • (一)appium-desktop定位元素原理
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • *上位机的定义
  • .aanva
  • .naturalWidth 和naturalHeight属性,
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .net core 依赖注入的基本用发
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .net framework4与其client profile版本的区别
  • .NET构架之我见
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .NET企业级应用架构设计系列之技术选型
  • .NET中统一的存储过程调用方法(收藏)
  • .sdf和.msp文件读取
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @Transactional 详解