LongAdder详解以及底层原理分析

ConcurrentHashMap源码篇:LongAdder原理分析 前言 最近在学习ConcurrentHashMap的源码,发现它采用了一种比较独特的方式对map中的元素数量进行统计,自然是要好好研究一下其原理思想,同时也能更好地理解ConcurrentHashMap本身。 本文主要思路分为以下4个部分 1.计数的使用效果 2.原理的直观图解 3.源码的细节分析 4.与AtomicInteger的比较 5.思想的抽象 学习的入口自然是map的put方法 public V put(K key, V value) { return putVal(k 阅读详情

一、原子累加器

我们都知道,原子整型可以在线程安全的前提下做到累加功能,而今天介绍的LongAdder具有更好的性能

我们先来看原子累加器和原子整型做累加的对比使用:

    private static <T> void demo(Supplier<T> supplier, Consumer<T> action){
        T adder = supplier.get();
        long start = System.nanoTime();
        List<Thread> ts = new ArrayList<>();
        for (int i = 0;i<40;i++){
            ts.add(new Thread(()->{
                for (int j = 0;j<500000;j++){
                    action.accept(adder);
                }
            }));
        }
        ts.forEach(t->t.start());
        ts.forEach(t->{
            try {
                t.join();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        });
    }

    public static void main(String[] args) {
        for (int i = 0;i<5;i++){
            demo(()->new LongAdder(),longAdder -> longAdder.increment());
        }
        for (int i = 0;i<5;i++){
            demo(()->new AtomicLong(),atomicLong -> atomicLong.getAndIncrement());
        }
    }

通过上面的代码运行我们可以清晰地看到,两种方式都有效的产完成了累加的效果,但是明显使用累加器的效率要更好,甚至要高出原子类型累加好几倍。

现在,我们可以简单地理解为,原子累加器就是JAVA在并发编程下提供的有保障的累加手段。

二、LongAdder执行原理

LongAdder之所以性能提升这么多,就是在有竞争时,设置多个累加单元,不同线程累加不同的累加单元,最后在将其汇总,减少了cas重试失败,从而提高了性能。

简单来说,累加器就是将需要做累加的共享变量,分成许多部分,时多个线程只累加自己的部分(这样做既可以减少使用普通整型容易出现的线程不安全错误,也可以提高原子类型在累加时效率底下的问题),足以后再将结果汇总,得到累加结果。

就比如银行要清点大量钞票,一个人来清点效率低下,所以需要多个人来(多个线程),将大量钞票分给多个员工(分配累加单元),每个员工仅仅需要对自己的那部分钞票清点(每个线程累加自己的累加单元),最后将结果汇总起来,就是所有钞票的总数。

LongAdder中有几个关键域:

transient volatile Cell[] cells;//累加单元数组,懒惰初始化
transient volatile long base;//基础值,如果是单线程没有竞争,则用cas累加这个域
transient volatile int cellsBusy;//zaicell创建或扩容时,置位1,表示加锁

其中cells就是累加单元,用来给各个线程分配累加任务。

base用来做单线程的累加,同时还有汇总的作用,也是就是说base=cells[0]+cells[1]……+base

cellbase则用来表示加锁置位,0表示无锁,1表示加锁。

注意:

此处cellsbusy所说的锁并不是真正的对象锁,而是底层用cas来模拟加锁。

cas模拟加锁:

当占用某资源需要模拟加锁时,cas会将某处标志位的初始态变为加锁态(如将0改为1)。此时当出现竞争时,其他线程同样会尝试cas操作,但均以失败告终,所以会不停尝试cas,起到了加锁的功效。

Cell

@sun.misc.Contended static final class Cell {
        volatile long value;
        Cell(long x) { value = x; }
        final boolean cas(long cmp, long val) {
            return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
        }

        // Unsafe mechanics
        private static final sun.misc.Unsafe UNSAFE;
        private static final long valueOffset;
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> ak = Cell.class;
                valueOffset = UNSAFE.objectFieldOffset
                    (ak.getDeclaredField("value"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

 在Cell类源码中我们能看出,cell底层也是采用cas来做累加计数。

三、伪共享

我们都知道cpu内存模型

因为 CPU 与内存的速度差异很大,需要靠预读数据至缓存来提升效率。而缓存以缓存行为单位,每个缓存行对应着一块内存,一般是64 byte (8个 long )

缓存的加入会造成数据副本的产生,即同一份数据会缓存在不同核心的缓存行中。

CPU 要保证数据的一致性,如果某个 CPU 核心更改了数据,其它 CPU 核心对应的整个缓存行必须失效

也就是说,在同一缓存行中的缓存的内容时时刻刻都是相同的,这样就违背了我们cells的初衷。

如图,因为cells是数组类型,导致他们在内存中始终处于连续存储状态。当任何一个线程改变cell中的值时,另一个线程中的缓存必然会失效(缓存是以行为单位进行更新),这样繁杂的操作使得效率大大降低。

问题解决

@ sun . misc . Contended 用来解决这个问题,它的原理是在使用此注解的对象或字段的前后各增加128字节大小的 padding 从而让 CPU 将对象预读至缓存时占用不同的缓存行,这样,不会造成对方缓存行的失效。

也就是说,增加无用的内存空间是cells扩容,从而在缓存中,每一个cell能占据一个缓存行,也就解决了失效的问题。
 

 

LongAdder原理分析和性能测试 介绍 LongAddr是JDK1.8才有的。其在高并发情况下,相比与AtomicLong的性能更高。本篇主要分析一下其实现原理。并且与AtomicLong做一个性能对比测试。 AtomicLong利用CPU对CAS实现的原子化指令实现。 public final long getAndAddLong(Object var1, long var2, long var4) { long var6; do { var6 = this.getLongVolatile(var1, va 阅读详情

相关推荐

【Java核心高阶进阶】31-CAS与原子类

比较内存位置 V 的当前值是否等于预期旧值 A,若相等则将 V 更新为新值 B,否则不做任何操作。整个操作是原子的、不可中断的。CAS 是一种乐观锁思想:不加锁,先操作,提交时检查冲突。这与 synchronized 的悲观锁策略形成鲜明对比——悲观锁假设一定会发生冲突,先加锁再操作;乐观锁假设大概率没有冲突,直接操作,失败则重试。

gaochufukanyongren的博客 9

并发编程(二十八) - LongAdder原理

并发编程(二十八) - LongAdder原理

及时当勉励,岁月不待人 1851

【java】LongAdder源码分析原理分析

文章目录1.概述1.1 为何要引入LongAdder?2.LongAdder案例3.LongAdder源码分析3.1 设计思路3.2 数据对比3.3 add3.3.1 longAccumulate3.3.1.1 第2种情况-初始化3.3.1.2 第一种情况-竞争到锁3.3.1.3 扩容3.3.1.4 第3种情况M.参考 1.概述 先参考使用相关的文档: 高并发中计数器的实现方式有哪些? 【java】阿里为什么推荐使用LongAdder,而不是volatile? 针对JDK中的原子类,想必大家都熟悉Atom

九师兄 363

LongAdder原理浅析

LongAdder原理浅析

liulianglin的专栏 5149

Java并发工具类LongAdder原理实例解析

主要介绍了Java并发工具类LongAdder原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

STM32F103+LAN9252实战:从站代码迁移中的5个硬件坑与解决方案

本文分享了将EtherCAT从站代码从STM32F767迁移至STM32F103平台时,搭配LAN9252遇到的五个典型硬件问题及解决方案。核心挑战包括时钟源不匹配、FSMC时序配置、中断映射错误、片选资源不足以及Flash烧录异常。文章通过实战经验,强调了硬件差异对代码迁移的关键影响,并提供了具体的调试思路与配置方法。

p5l2m9n4o6q的博客 697

一文看懂LongAdder原理

前面介绍了Java中的一些原子类,但是基本都是通过CAS来实现原子性操作,白白浪费CPU资源。JDK8中新增了一个原子性递增或者递减类LongAdder用来克服高并发下使用AtomicLong的缺点。LongAdder的思路是把一个变量分解为多个变量,让同样多的线程去竞争多个资源。如图所示: 使用LongAdder时,内部维护了多个Cell变量,每个Cell里面有一个初始值为0的long型变量,这样同时争取一个变量的线程就变少了,而是分散成对多个变量的竞争,减少了失败次数。如果竞争某个Cell变.

Lucky_xiang 3162

避坑指南:Xilinx SelectIO IP核官方例程里那些容易忽略的细节(复位、时钟与数据回环)

本文深入解析Xilinx SelectIO IP核设计中复位策略、时钟域交互和数据回环验证三大关键领域的实战避坑技巧。针对官方例程中易被忽视的细节,如复位同步链深度、时钟相位约束和数据对齐机制,提供经过项目验证的优化方案,帮助工程师节省80%以上的调试时间。特别适用于FPGA开发中高速接口设计场景。

weixin_42561476的博客 448

Java LongAdder类介绍、代码示例、底层实现原理及与分段锁的区别

LongAdder是Java并发包(java.util.concurrent)中的一个类,用于高效地实现多线程环境下的加法操作。在多线程环境中,如果多个线程同时对同一个变量进行加法操作,会存在竞争条件(race condition)。传统的加法操作使用synchronized关键字或者锁来保证线程安全,但是在高并发情况下,竞争条件会导致性能瓶颈。LongAdder类通过一种更加高效的方式来解决这个问题。LongAdder内部维护了一个或多个变量,这些变量被称为"cell"。

学亮编程手记 5533

自抗扰(ADRC)控制原理及控制器设计

自抗扰控制原理以及控制器设计

weixin_43487974的博客 3万+

基于深度残差U-Net与多尺度注意力机制的医学图像分割系统

本文提出了一种创新的医学图像分割系统,通过融合残差连接、通道注意力机制和空间金字塔池化技术,构建了高性能的UResnet分割网络。系统采用编码器-解码器架构,创新性地引入多层次特征增强模块,显著提升了医学图像中复杂组织结构的分割精度。实验结果表明,该方案在多个医学图像数据集上均取得了优异性能,边界分割精度提升15%,训练收敛速度提升30%,同时减少20%计算量。系统为临床诊断提供了可靠的技术支持,未来可扩展至3D医学图像分割和联邦学习等方向。

Henry的博客 814

LongAdder的原理

LongAdder的原理

qq_38304915的博客 1492

Lion优化器试验笔记

Lion优化器试验笔记

jacke121的专栏 847

LongAdder原理分析

LongAdder由来 LongAdder类是JDK1.8新增的一个原子性操作类。AtomicLong通过CAS算法提供了非阻塞的原子性操作,相比受用阻塞算法的同步器来说性能已经很好了,但是JDK开发组并不满足于此,因为非常搞并发的请求下AtomicLong的性能是不能让人接受的。 如下AtomicLong 的incrementAndGet的代码,虽然AtomicLong使用CAS算法,但是CA...

大佬请赐教 1万+

飞牛fnNAS搭建Web网页版OFFICE(WPS)软件

本文介绍了如何在飞牛NAS上通过Docker容器部署WPS Office办公软件。主要内容包括:启用Docker服务、准备项目文件夹结构、使用Compose方式构建容器、解决端口冲突问题、配置中文输入法和字体库,以及通过ZeroTier实现远程访问。文章详细说明了每个步骤的操作方法,包括容器启动、输入法设置、字体添加和文件存储位置配置。最后还介绍了使用ZeroTier内网穿透技术实现远程访问NAS上WPS服务的方法,让用户可以在不同设备上随时编辑NAS中的文件。整个部署过程完整清晰,为NAS用户提供了便捷的

dgnankai的专栏 1701

AI测试:手把手教你用AI创建流程图「喂饭教程」

本文介绍了如何利用next-ai-draw-io开源项目,通过AI快速生成专业流程图,提升测试工作效率。该工具支持自然语言交互,兼容多种AI模型(如OpenAI、Claude等),并集成draw.io图表引擎,实现实时编辑。

blues_C的博客 759

LongAdder原理

前面介绍了Java中的一些原子类,但是基本都是通过CAS来实现原子性操作,白白浪费CPU资源。JDK8中新增了一个原子性递增或者递减类LongAdder用来克服高并发下使用AtomicLong的缺点。LongAdder的思路是把一个变量分解为多个变量,让同样多的线程去竞争多个资源。如图所示: 使用LongAdder时,内部维护了多个Cell变量,每个Cell里面有一个初始值为0的long型变量,...

reachwang的博客 4277

MeloTTS 生成 RKNN 模型

摘要: 本方案基于RK3588平台,利用RKNN工具链实现高效语音合成(TTS)。采用MeloTTS开源模型,支持中英文混合语音生成。部署流程包括:1) 导出ONNX模型;2) 转换为RKNN格式;3) 在RK3588开发板运行。关键步骤包含环境配置(RKNN Toolkit2≥1.4.0)、模型转换(非量化处理)及音频处理实现。方案充分发挥RK3588的NPU加速能力,适用于边缘设备语音合成场景

J。 347

LongAdder引入、原理、Striped64、分散热点思想、深度解析LongAdder源码、LongAdder和AtomicLong区别

LongAdder引入、原理、Striped64、分散热点思想、深度解析LongAdder源码、LongAdder和AtomicLong区别

m0_74969835的博客 1383

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

LongAdder使用及原理浅析(对比AtomicLong进行分析)

对比AtomicLong,分析LongAdder工作原理及使用案例

liulianglin的专栏 1406

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

LongAdder类实现原理、源码解析

1. 概述 AtomicLong通过循环CAS实现原子操作,缺点是当高并发下竞争比较激烈的时候,会出现大量的CAS失败,导致循环CAS次数大大增加,这种自旋是要消耗时间cpu时间片的,会占用大量cpu的时间,降低效率。那这个问题如何解决呢?JUC给我们提供了一个类,LongAdder, 它的作用和AtomicLong是一样的,都是一个实现了原子操作的累加器,LongAdder通过维护一个基准值base和 Cell 数组,多线程的时候多个线程去竞争Cell数组的不同的元素,进行cas累加操作...

NokeNoke的博客 3520

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

高并发计数器LongAdder 实现原理与使用场景详解

设计要点实现方案解决的问题竞争分散分片 Cell 数组降低 CAS 失败率伪共享预防@Contended 注解提升缓存利用率动态扩容按需创建 Cell平衡性能与内存延迟初始化初始使用 base 变量减少内存开销最终一致性sum() 合并所有 Cell保证最终结果正确性通过理解 LongAdder 的设计哲学和实现细节,开发者可以在高并发场景中做出更优的技术选型,在保证线程安全的前提下实现5-10 倍的性能提升。

fjkxyl的博客 1014

LongAdder讲解

思维导图.png 阿里巴巴开发手册.png 对于Java项目中计数统计的一些需求,如果是 JDK8,推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数) 在大多数项目及开源组件中,计数统计使用最多的仍然还是AtomicLong,虽然是阿里巴巴这样说,但是我们仍然要根据使用场景来决定是否使用LongAdder。 今天主要是来讲讲LongAdder的实现原理,还是老方式,通过图文一步步解开LongAdder神秘的面纱,通过此篇文章你会了解到: ...

JMU_software19的博客 2020

19.Atomic系列之LongAdder的底层原理(分段锁提升并发性能)

什么是分段锁?分段锁思想怎么减少并发竞争,提升并发性能?LongAdder是怎么实现分段锁思想的?

chenzengnian123的博客 2232

LongAdder源码分析

LongAdder

syk123839070的博客 1111
上一篇: 原子类型详解
下一篇: ReentrantReadWriteLock原理详解
MiaSanMiaRL
博客等级 码龄6年 19粉丝 40原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值