Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Long型原子操作之AtomicLong与LongAdder

Long型原子操作之AtomicLong与LongAdder

作者头像
一个架构师
发布于 2022-06-20 12:02:19
发布于 2022-06-20 12:02:19
44600
代码可运行
举报
运行总次数:0
代码可运行

在JVM中long和double型变量都是占用8个字节空间存储的, 而在读写时,是以4字节为单位操作的; 也就是要写入一个long型数据, 需要分别写入高位和低位, 共2次完成.

所以long和double是天生的线程不安全; 要在线程间共享long或者double变量, 必须放在锁内或synchronized代码块中执行, 或是将变量声明为volatile类型.

AtomicLong

在并发较少场景下, 可以使用AtomicLong解决并发的原子性问题, 与之前讲的AtomicInteger类似,利用volatile和CAS机制完成. 因为每次读写都是2次操作,相对AtomicInteger而言效率是较低的.

LongAdder

JDK8中, 为优化AtomicLong在高并发下的低效问题, 引入了一个新的Long型原子操作类LongAdder, 它比AtomicLong拥有更好的性能, 当然代价就是消耗更多的空间.

数据写入

在LongAdder中数据是其父类Striped64中的两个变量base, cells[]共同存储的.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Table of cells. When non-null, size is a power of 2.
 */
transient volatile Cell[] cells;
/**
 * Base value, used mainly when there is no contention, but also as
 * a fallback during table initialization races. Updated via CAS.
 */
transient volatile long base;

Striped64: 是一个处理累加的高并发工具类.

base: 是在没有线程竞争时, 数据的CAS处理部分;

cells[]: 是在有线程竞争时, 数据的处理部分;

有无线程竞争的判断依据就是在对base进行CAS操作时是否成功.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
casBase(b = base, b + x)

在使用cells, 首先会根据当前线程ID和数组长度, 计算该使用cells数组中哪个元素进行CAS计算.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(a = as[getProbe() & m]) == null

综上, 采用了分治的思想, 数据操作由原来1个位置, 分散到了base和cells[]数组的多个位置, 降低了数据锁的概率, 提高了运算效率.

数据读取

数据的读取是base和cells[]数组累加得到的.

在高并发下, 累计过的数据可能被其他线程修改了, 导致出现误差.

Cells[]初始化

执行写入出现竞争时, cells[]数组就会调用longAccumulate()方法进行初始化处理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void add(long x) {
    ...  
    !(uncontended = a.cas(v = a.value, v + x)))
   longAccumulate(x, null, uncontended);
    ... 
}

Cells[]初始化时会根据线程的探针哈希值初始化cells[]数组长度.

探针哈希值的作用是将线程和数组中的不同元素对应起来, 尽量避免线程争用同一数组元素.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static final int getProbe() {
    return UNSAFE.getInt(Thread.currentThread(), PROBE);
}

LongAdder与AtomicLong的比较

LongAdder和AtomicLong虽都能实现对long型数字的计数, 但他们还是有些区别的.

1. 从API上说, LongAdder只提供了加1和减1的相关方法, 而AtomicLong可以处理任意数, 使用上也更灵活, 也提供了更多的使用方式.

2. 从性能上说, 在并发量高的情况下, LongAdder造成锁的概率更低, 性能更高, 但在get时可能有误差. 一般情况下, AtomicLong都是可以满足性能需要的.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从码农的全世界路过 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JDK 8 新增的 LongAdder,得过来看一下!
" 在介绍 AtomicInteger 时,已经说明在高并发下大量线程去竞争更新同一个原子变量时,因为只有一个线程能够更新成功,其他的线程在竞争失败后,只能一直循环,不断的进行 CAS 尝试,从而浪费了 CPU 资源。而在 JDK 8 中新增了 LongAdder 用来解决高并发下变量的原子操作。下面同样通过阅读源码来了解 LongAdder 。 "
程序员小航
2020/11/23
3940
JDK 8 新增的 LongAdder,得过来看一下!
Java8原子弹类之LongAdder源码分析
JDK 8开始,针对Long型的原子操作, Java又提供了LongAdder. LongAccumulator; 针对Double类型,Java提供了DoubleAdder、DoubleAccumulator。
JavaEdge
2022/01/25
3400
Java8原子弹类之LongAdder源码分析
LongAdder源码分析
并发环境重计数 AtomicLong 的 Add 操作是依赖自旋不断的 CAS 去累加一个 Long 值。如果在竞争激烈的情况下,CAS 操作不断的失败,就会有大量的线程不断的自旋尝试 CAS 会造成 CPU 的极大的消耗。
leobhao
2022/06/28
2910
LongAdder源码分析
LongAdder源码【原创+图解+视频讲解】
【总结者】LongAdder源码讲解(图解+代码逐行分析)4K面试必看_哔哩哔哩_bilibili
编程张无忌
2023/01/06
3770
LongAdder源码【原创+图解+视频讲解】
LongAdder解析
 对LongAdder的最初了解是从Coolshell上的一篇文章中获得的,但是一直都没有深入的了解过其实现,只知道它相较于AtomicLong来说,更加适合写多读少的并发情景。今天,我们就研究一下LongAdder的原理,探究一下它如此高效的原因。
程序员历小冰
2019/01/24
4640
LongAdder解析
LongAdder 源码分析
按照作者的说法,LongAdder 在多个线程更新下比 AtomicLong 性能更好,但要消耗更多的空间
itliusir
2020/02/10
5640
比AtomicLong更优秀的LongAdder确定不来了解一下吗?
文章中所有高清无码图片在公众号号回复: 图片666 即可查阅, 可直接关注公众号:壹枝花算不算浪漫
一枝花算不算浪漫
2020/05/15
1.1K0
高性能原子类
公共父类Striped64是实现中的核心,它实现一些核心操作,处理64位数据,很容易就能转化为其他基本类型,是个通用的类。二元算术运算,指的是你可以给它提供一个二元算术方式,这个类按照你提供的方式进行算术计算,并保存计算结果。二元运算中第一个操作数是累积器中某个计数单元当前的值,另外一个值是外部提供的。
黑洞代码
2021/01/14
6410
高性能原子类
《从Java面试题看源码》-LongAdder、LongAccumulator是个什么东西?
LongAdder 继承自Striped64,并实现了Serializable序列化接口。
阿提说说
2022/12/02
6710
LongAdder的源码学习与理解
因为CPU与内存之间速度还是存在较大差距所以现在计算机在内存与CPU之间引入了三级缓存
才疏学浅的木子
2022/11/13
2400
LongAdder的源码学习与理解
Java8 原子弹类之LongAdder源码分析add使用场景 LongAdder是否能够替换AtomicLong
简单来说,这个类用于在多线程情况下的求和。 官方文档的说明 从关键方法 add 包含了一个Cell数组,Striped64的一个内部类 Padded variant of Atomic
JavaEdge
2018/05/16
1.5K0
从 LongAdder 中窥见并发组件的设计思路
最近在看阿里的 Sentinel 的源码的时候。发现使用了一个类 LongAdder 来在并发环境中计数。这个时候就提出了疑问,JDK 中已经有 AtomicLong 了,为啥还要使用 LongAdder ? AtomicLong 已经是基于 CAS 的无锁结构,已经有很好的并发表现了,为啥还要用 LongAdder ?于是赶快找来源码一探究竟。
用户2060079
2018/12/19
6800
并发编程原理剖析——Java并发包中原子操作类原理剖析
代码(1)通过Unsafe。getUnsafe()方法获取到Unsafe类的实例,因为AtomicLong类也是在rt.jar包下的,AtomicLong类就是通过BootStrap类加载器加载的。
须臾之余
2019/07/10
5390
并发编程原理剖析——Java并发包中原子操作类原理剖析
Java Review - 并发编程_JDK 8新增的原子操作类LongAdder & LongAccumulator
Java Review - 并发编程_原子操作类原理剖析中提到了 AtomicLong通过CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器来说它的性能已经很好了,但是JDK开发组并不满足于此。使用AtomicLong时,在高并发下大量线程会同时去竞争更新同一个原子变量,但是由于同时只有一个线程的CAS操作会成功,这就造成了大量线程竞争失败后,会通过无限循环不断进行自旋尝试CAS的操作,而这会白白浪费CPU资源。
小小工匠
2021/12/01
2710
Java Review - 并发编程_JDK 8新增的原子操作类LongAdder & LongAccumulator
Java原子操作Atomic类详解
      1.CAS(Compare And Swap,比较并交换),通常指的是这样一种原子操作:
忧愁的chafry
2022/10/30
7480
Java原子操作Atomic类详解
死磕 java并发包之LongAdder源码分析
LongAdder是java8中新增的原子类,在多线程环境中,它比AtomicLong性能要高出不少,特别是写多的场景。
彤哥
2019/07/08
3930
死磕 java并发包之LongAdder源码分析
多线程编程学习八(原子操作类).
Java 在 JDK 1.5 中提供了 java.util.concurrent.atomic 包,这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。主要提供了四种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性。
JMCui
2019/09/09
3140
多线程编程学习八(原子操作类).
六个面试题层层剖析——LongAddr原子类 顶
可以看到,Cell的构造很简单,其内部维护一个被声明为Volatile的变量,保证了内存的可见性。
须臾之余
2019/07/18
9390
六个面试题层层剖析——LongAddr原子类
                                                                            顶
LongAdder(下)代码实现原理
为了解决高并发下多线程对一个变量CAS争夺失败后进行自旋而造成的降低并发性能的问题,LongAdder在内部维护多个Cell元素**(一个动态的Cell数组)**来分担单个变量进行争夺开销。下面围绕以下话题从源码角度来分析LongAdder的实现!
YanL
2020/04/29
5260
LongAdder(下)代码实现原理
19.Atomic系列之LongAdder的底层原理(分段锁提升并发性能)
老王:小陈啊,上一章我们讲解了cas的缺陷,无法同时更新多个变量、以及ABA的问题。以及如果使用AtomicReference解决同时更新多个变量,如果使用AtomicStampedReference解决ABA的问题,这些都还记得不?
终有救赎
2023/10/16
2190
19.Atomic系列之LongAdder的底层原理(分段锁提升并发性能)
相关推荐
JDK 8 新增的 LongAdder,得过来看一下!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验