深入探讨Java中的LongAdder:使用技巧与避坑指南
文章目录
- 一、什么是LongAdder?
- 二、LongAdder的简单使用
- 示例代码:
- 三、LongAdder的工作原理
- 四、LongAdder的常见使用场景
- 五、使用LongAdder时的注意事项(避坑指南)
- 1. 不要滥用LongAdder
- 2. sum()方法与精度问题
- 3. 避免过度使用reset()
- 4. 不能用于CAS依赖的场景
- 六、LongAdder与AtomicLong的区别
- 七、总结
- 推荐阅读文章
在高并发编程中,如何高效地计数或累加值是一个常见问题。Java提供了很多工具来应对这些场景,其中
LongAdder
是一个在高并发环境下性能优于
AtomicLong
的类。它是如何工作的?我们如何正确使用它,并避免常见的坑?接下来,我们将通过简单易懂的方式,帮助你理解
LongAdder
。
一、什么是LongAdder?
LongAdder
位于java.util.concurrent.atomic
包中,是一种用于高效计数的类。它的功能类似于AtomicLong
,但设计上更适合在高并发环境下使用。
AtomicLong
依赖于底层的**CAS(Compare-And-Swap)**机制,它通过不断重试来保证原子性。然而,在极高并发的场景中,CAS操作可能会频繁失败,导致性能下降。而LongAdder
通过将计数分散到多个单独的变量中,并在最后累加,减少了竞争,从而在高并发场景下提升性能。
二、LongAdder的简单使用
LongAdder
的使用非常简单,与AtomicLong
类似。你可以使用increment()
方法进行累加,用sum()
来获取总值。
示例代码:
import java.util.concurrent.atomic.LongAdder;public class LongAdderExample {public static void main(String[] args) {// 创建LongAdder实例LongAdder longAdder = new LongAdder();// 执行累加操作longAdder.increment();longAdder.increment();longAdder.add(10); // 增加指定值// 获取当前累加的总值long sum = longAdder.sum();System.out.println("总计数值: " + sum); // 输出:12// 重置LongAdderlongAdder.reset();System.out.println("重置后总值: " + longAdder.sum()); // 输出:0}
}
三、LongAdder的工作原理
LongAdder
的核心思想是分段累加,即通过将计数分散到多个变量中(称为“槽”或“单元”),每个线程在并发访问时操作不同的单元,减少竞争。最后,当你调用sum()
方法时,所有的单元的值会被汇总,得到最终的总值。
这种设计在低竞争时开销较大,因为每次操作需要涉及多个变量,而在高并发时则能大幅减少CAS失败的重试,提高整体性能。
简单理解:
- 在低并发时,
AtomicLong
表现会更好,因为不需要额外的分段。 - 在高并发场景下,
LongAdder
避免了频繁的CAS冲突,能显著提升效率。
四、LongAdder的常见使用场景
LongAdder
特别适合用于高并发计数器场景,例如:
- Web请求统计:记录每秒钟的访问请求数。
- 日志系统中的日志条目计数:用于记录日志条目在多线程写入的总数。
- 性能分析工具:高并发系统中某些操作的频次统计。
五、使用LongAdder时的注意事项(避坑指南)
虽然LongAdder
的性能在高并发下非常出色,但使用时也有一些注意事项需要小心。
1. 不要滥用LongAdder
LongAdder
的优势主要体现在高并发场景下。如果你的应用并发量较低或只是进行简单的累加操作,那么使用AtomicLong
更为合适,因为LongAdder
在低并发下反而会有更高的开销。
解决方法:评估你的应用场景,如果并发量不高,优先使用AtomicLong
,只有在并发量较大时才使用LongAdder
。
2. sum()方法与精度问题
由于LongAdder
的累加操作是分散到多个单元的,sum()
方法是对这些单元进行汇总。因此,当你调用sum()
时,可能无法得到瞬时的精确值,特别是在多个线程正在同时进行累加操作时。
解决方法:如果你需要在一个时刻获得精确的计数值,LongAdder
可能不适合你。对于大多数场景,这种近似值是可以接受的。
3. 避免过度使用reset()
LongAdder
提供了reset()
方法来重置计数器,但要小心:reset()
只是将累加器清零,且不会对每个线程的单元做特殊处理。在高并发的情况下,reset()
后的新累加操作可能会受到原先单元状态的影响,导致不一致的行为。
解决方法:尽量避免在并发操作过程中频繁使用reset()
,如果必须使用,确保在恰当的时机(如所有操作已完成时)调用。
4. 不能用于CAS依赖的场景
虽然LongAdder
在累加操作中表现出色,但它并不支持AtomicLong
的CAS操作。如果你的应用场景需要进行基于比较的原子性操作(如compareAndSet()
),那AtomicLong
是你更好的选择。
六、LongAdder与AtomicLong的区别
功能/特性 | LongAdder | AtomicLong |
---|---|---|
性能 | 高并发场景下性能优于AtomicLong | 在低并发场景下表现更好 |
原子性 | 适合累加操作,但不支持compareAndSet() | 支持compareAndSet() 等CAS操作 |
开销 | 分散到多个单元,低并发时有额外开销 | 简单直接,开销较小 |
使用场景 | 高并发计数器 | 需要单步原子性操作或低并发计数场景 |
七、总结
LongAdder
是什么? 它是AtomicLong
的替代品,设计用于高并发环境下的高效计数。- 如何使用? 提供了
increment()
、add()
、sum()
等简单的方法,帮助你进行线程安全的累加操作。 - 避坑指南? 注意避免在低并发下使用
LongAdder
,小心reset()
操作带来的潜在问题,并且LongAdder
无法用于需要CAS操作的场景。
通过正确使用LongAdder
,你可以在高并发场景下更高效地进行计数操作,但在选择它之前,务必先评估你的需求和场景,确保它是最佳选择。
推荐阅读文章
- 使用 Spring 框架构建 MVC 应用程序:初学者教程
- 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
- 如何理解应用 Java 多线程与并发编程?
- Java Spring 中常用的 @PostConstruct 注解使用总结
- 线程 vs 虚拟线程:深入理解及区别
- 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
- 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
- “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
- Java 中消除 If-else 技巧总结
- 线程池的核心参数配置(仅供参考)
- 【人工智能】聊聊Transformer,深度学习的一股清流(13)
- Java 枚举的几个常用技巧,你可以试着用用
- 如何理解线程安全这个概念?
- 理解 Java 桥接方法
- Spring 整合嵌入式 Tomcat 容器
- Tomcat 如何加载 SpringMVC 组件
相关文章:
深入探讨Java中的LongAdder:使用技巧与避坑指南
文章目录 一、什么是LongAdder?二、LongAdder的简单使用示例代码: 三、LongAdder的工作原理四、LongAdder的常见使用场景五、使用LongAdder时的注意事项(避坑指南)1. 不要滥用LongAdder2. sum()方法与精度问题3. 避免过度使用rese…...

【本科毕业设计】基于单片机的智能家居防火防盗报警系统
基于单片机的智能家居防火防盗报警系统 相关资料链接下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系…...

C语言 动态数据结构的C语言实现单向链表-2
建立一个单向链表 在单向链表中查找节点---查找尾节点 在单向链表中查找节点 --- 查找第 n 个节点 向单向链表中插入一个节点 向单向链表的尾部插入一个节点 向单向链表中某节点后插入一个节点 向单向链表中插入一个节点 删除单向链表中的某一节点 链表 vs 数组 动态数据结构...
Github 2024-10-23C开源项目日报 Top10
根据Github Trendings的统计,今日(2024-10-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10PLpgSQL项目1Redis - 内存数据库和数据结构服务器 创建周期:5411 天开发语言:C协议类型:BSD 3-Clause “New” or “Revised” Licen…...
ubuntu20.04 opencv4.0 /usr/local/lib/libgflags.a(gflags.cc.o): relocation报错解决
在一个只有ubuntu20.04的docker环境中配置opencv4.0.0, 什么库都没有,都要重新安装, 其他的问题在网上都找到了解决方案,唯独这个问题比较棘手: [ 86%] Linking CXX executable …/…/bin/opencv_annotation /usr/bin/ld: /usr/lo…...

android openGL ES详解——混合
一、混合概念 混合是一种常用的技巧,通常可以用来实现半透明。但其实它也是十分灵活的,你可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象。混合是什么呢?混合就是把两种颜色混在一起。具体一点,就…...

计网--物理层
目录 物理层的任务 1、常见概念 2、信道极限容量 3、传输介质 (1)导引型传输介质 (2)非导引型传输介质 4、信道复用技术 (1)频分 / 时分 复用 (2)波分复用WDM (…...

算法的学习笔记—数组中的逆序对(牛客JZ51)
😀前言 在算法和数据结构领域,"逆序对"是一个经典问题。它在数组中两个数字之间定义,若前面的数字大于后面的数字,则这两个数字组成一个逆序对。我们要做的就是,给定一个数组,找出数组中所有的逆…...

Golang | Leetcode Golang题解之第498题对角线遍历
题目: 题解: func findDiagonalOrder(mat [][]int) []int {m, n : len(mat), len(mat[0])ans : make([]int, 0, m*n)for i : 0; i < mn-1; i {if i%2 1 {x : max(i-n1, 0)y : min(i, n-1)for x < m && y > 0 {ans append(ans, mat[x…...
什么是全局污染?怎么避免全局污染?
全局污染(Global Pollution)是指在编程过程中,过度使用全局变量或对象导致命名冲突、代码可维护性下降及潜在错误增加的问题。在 JavaScript 等动态语言中,尤其需要关注全局污染的风险。 全局污染的影响 1. 命名冲突 3. 意外修改…...

C# 串口通信教程
串口通信(Serial Communication)是一种用于设备之间数据传输的常见方法,通常用于与外部硬件设备(如传感器、机器人、微控制器)进行通信。在 C# 中,System.IO.Ports 命名空间提供了与串口设备交互的功能&…...
PHP编程基础
PHP(Hypertext Preprocessor,超文本预处理器)是一种广泛使用的开源服务器端脚本语言,主要用于网页开发,同时也可以进行命令行脚本编写。以下是PHP编程的基础知识: 1. PHP文件结构 PHP文件通常以 .php 为扩…...

TwinCAT3下位机配置EAP通讯传递与接收变量
添加EAP设备 DEVICE中右键选择添加新项,添加EAP(EtherCAT Automation Protocal)选择Network Variables类型,如下图。 设置网络适配器来激活EAP,在Adapter中选择search,选择网络适配器后确定,…...
近似推断 - 期望最大化(EM)篇
前言 近似推断是统计学和机器学习中一个至关重要的领域,尤其在处理复杂模型和不完全数据时显得尤为重要。期望最大化( Expectation Maximization \text{Expectation Maximization} Expectation Maximization,简称 EM \text{EM} EM࿰…...

arp欺骗及其实验
ARP欺骗(ARP Spoofing)是一种网络攻击技术,攻击者通过伪造ARP(地址解析协议)消息,将其MAC地址与目标IP地址关联,从而实现对网络流量的截获、篡改或重定向。以下是ARP欺骗的详细信息:…...
HDU The Boss on Mars(容斥原理)
题目大意: ACM 有 n 名员工,现在是他们从老板那里拿薪水的时候了。所有员工都从 1 到 n 编号。原因不明,如果员工的工作编号是 k,他今年可以获得 k^4 Mars 美元。所以为 ACM 工作的员工非常富有。 因为员工人数太多,…...

nnUnet 大模型学习笔记(续):训练网络(3d_fullres)以及数据集标签的处理
目录 1. 数据集处理 1.1 实现脚本 1.2 json文件 2. 设置读取路径 2.1 设置路径 2.2 数据集转换 2.3 数据集预处理 2.4 训练(3d_fullres) 3. 训练结果展示 关于nnUnet 数据集的处理和环境搭建,参考上文:第四章:nnUnet大模…...

Java中的数据结构与集合源码
目录 一、数据结构 1.1 数据结构概念 1.2 研究对象 1.3 常见存储结构 1.3.1 数组 1.3.2 链表 1.单向链表 2.双向链表 1.3.3 二叉树 1.3.4 栈(FILO,先进后出) 1.3.5 队列(FIFO,先进先出) 二、集合…...

Java应用程序的测试覆盖率之设计与实现(三)-- jacoco cli 客户端
一、背景 上文已把覆盖率数据采集好了,并提供远程连接的tcp地址及端口。 jacoco cli文档jacoco cli jar包 jacococli.jar 我下载好了,放在github工程里。 本文主要是介绍如何使用jacoco cli 客户端读取并生成覆盖率报告。 二、使用 1、dump覆盖率统…...

Deepin V23 / 统信UOS 下安装与配置 tftp
几个月前,我将开发系统从 ubuntu 切换到 Deepin,当时写过一篇文章《使用国产操作系统作为开发系统》。几个月下来,没有感觉有什么不适应,Ubuntu 能做的事情,在 Deepin 上都能做。而且有 UOS 应用商店的加持,…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...