尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Java进阶篇之LongAccumulator:把最大值统计交给可合并的函数
上一篇用LongAdder统计请求次数。如果接下来想观察“一批请求里最大的耗时”只做加法就不够了。每个线程提供自己的样本再把这些样本合成一个最大值这正是LongAccumulator适合表达的统计需求。本文以Java 21为适用版本沿着“函数、初始值、并发更新、批次读取”展开。示例数据是人为构造的教学样本单位为毫秒不代表真实接口测量。一、从累加次数走向自定义合并可以把LongAccumulator看成一个带合并规则的统计容器调用accumulate(value)提交样本调用get()读取合并后的值。加法、最大值和最小值都能成为规则但规则必须适合拆分后再合并。例如三组耗时分别是120、360、24080、980、310450、220、170。无论先处理哪一组最终最大值都应该相同。我们关注的是这批样本的极值样本的提交顺序不会改变答案。二、函数和identity要一起选择构造器接受一个LongBinaryOperator和一个identity。统计最大值可以写成LongAccumulatormaximumnewLongAccumulator(Long::max,Long.MIN_VALUE);初始值参与合并也用于归零后的恢复。对于最大值Long.MIN_VALUE不会压过任何合法long样本对于最小值可以使用Long.MAX_VALUE加法对应0。这个选择同时覆盖了负数样本。若把最大值初始值随手设为0一组全为负数的样本就会得到错误结果。合并函数需要满足三个要求结合律允许改变分组交换律允许改变顺序无副作用允许重试时再次计算。官方Java 21 LongAccumulator文档说明了这些约束以及最大值的identity选择。减法不满足这些条件。“把两个值相加再除以2”也不能直接用于平均值统计先平均哪两个数会影响最终结果。平均值可以分别收集总和与数量再在明确的统计边界计算。三、分散更新后怎样得到一个结果在OpenJDK21的实现中数据可能保存在base与多个Cell中读取时使用同一个函数合并。这是实现层面的组织方式单元数量和线程映射都无需由业务代码决定。可以结合OpenJDK21 LongAccumulator源码理解读取路径。图中的几个样本盒表示可参与合并的统计单元。对最大值来说合并局部最大值仍能得到整体最大值图示不表示每个线程永久占有一个固定盒子。四、完整示例并发提交批次结束后读取保存为LongAccumulatorDemo.java用JDK21编译运行importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;importjava.util.concurrent.atomic.LongAccumulator;publicclassLongAccumulatorDemo{publicstaticvoidmain(String[]args)throwsException{long[][]samples{{120,360,240},{80,980,310},{450,220,170},{600,90,700}};LongAccumulatormaximumnewLongAccumulator(Long::max,Long.MIN_VALUE);ListFuture?tasksnewArrayList();try(ExecutorServicepoolExecutors.newFixedThreadPool(4)){for(long[]batch:samples){tasks.add(pool.submit(()-{for(longvalue:batch){maximum.accumulate(value);}}));}for(Future?task:tasks){task.get();}}System.out.println(maximummaximum.get());System.out.println(finishedBatchmaximum.getThenReset());System.out.println(emptymaximum.get());maximum.accumulate(-12);maximum.accumulate(-4);System.out.println(negativeBatchmaximum.get());}}javac LongAccumulatorDemo.javajavaLongAccumulatorDemo在JDK21.0.8中实际运行得到maximum980 finishedBatch980 empty-9223372036854775808 negativeBatch-4这里有两个值得留意的细节。首先Future.get()等待所有任务完成并把任务异常传回主线程读取结果时这个示例已经没有后台写入。其次getThenReset()后恢复的是构造时传入的identity所以empty显示Long.MIN_VALUE。空容器的值是一种初始化状态。实际统计服务可以另外记录样本数在没有样本时展示“暂无数据”避免把这个极小值当成真正的耗时。五、实时观察和精确批次各有边界get()返回的结果为非原子快照并发更新期间可能漏掉读取过程中新到达的更新。reset()与getThenReset()需要明确的静止点边写边清零不能保证精确划分批次。官方方法说明明确指出了这一点。需求更合适的处理方式观察多线程样本的最大值或最小值LongAccumulator配合合适函数与identity精确读取一批完成任务的极值等待任务结束再get或getThenReset仅计数或求和LongAdder语义更直接根据当前值批准配额、分配唯一序号使用AtomicLong、CAS或业务协调机制精确按时间窗口分桶先设计窗口交接与写入归属再选择统计容器LongAccumulator不会替你规定某个样本属于哪一分钟也不会把“检查阈值”和“批准动作”组合成事务。选型时先写清读取语义后面的实现会更稳妥。六、 思维导图LongAccumulator合并规则结合律与交换律函数无副作用初始值最大值用MIN_VALUE归零回到identity并发统计accumulate提交样本get合并读取使用边界读取非原子快照批次结束再清零七、总结总结要点合并规则决定适用范围。LongAccumulator适合可以拆分、重新分组和交换顺序的统计任务。最大值是一个直观的入口identity也要与规则匹配。读取时机决定结果含义。实时观察可以接受读数滞后精确批次需要先完成写入再读取和清零。示例里的等待步骤承担了这个边界。容器之外还有业务协议。样本数、窗口归属与配额决策需要单独设计不能从一个统计值直接推断协调操作已经安全。下一篇继续学习AtomicReference看看对象引用更新与不可变状态快照怎样配合。如果你觉得这篇文章对你有所帮助欢迎点赞、收藏、分享
RELATED

相关推荐

Skills Manager:跨平台AI编程工具技能统一管理实战

Skills Manager:跨平台AI编程工具技能统一管理实战

桌面上开着七八个终端窗口,Claude Code里跑着网页转Markdown的Skill,Cline里又有一份从零写的同款提示词,Cursor的Rules里还躺着一个凑合能用的版本——这是我接触Skills Manager之前最真实的日常。所谓Skills Manager,往浅了说&a…

📅 2026/10/4 5:42:45
用GLiNER2.5-Decide搭建客服自动路由:意图识别、工单分流与人工升级的完整清单

用GLiNER2.5-Decide搭建客服自动路由:意图识别、工单分流与人工升级的完整清单

用GLiNER2.5-Decide搭建客服自动路由:意图识别、工单分流与人工升级的完整清单 【免费下载链接】GLiNER2.5-Decide 项目地址: https://ai.gitcode.com/hf_mirrors/fastino/GLiNER2.5-Decide GLiNER2.5-Decide 是一个 340M 参数的英文分类模型,专…

📅 2026/10/4 5:42:45
96760 词元 8 毫秒恢复:MTPLX 会话缓存与 SSD 持久化机制详解

96760 词元 8 毫秒恢复:MTPLX 会话缓存与 SSD 持久化机制详解

96760 词元 8 毫秒恢复:MTPLX 会话缓存与 SSD 持久化机制详解 【免费下载链接】MTPLX The fastest way to run Qwen 3.8 Flash Next, Qwen 3.8 27B and Ternary Bonsai 2 27B on a Mac: 125 tok/s in OpenCode on an M5 Max, and a 27B model on 16 GB Macs. Native MTP specul…

📅 2026/10/4 5:42:45
MORE NEWS

更多资讯

📰

Obsidian + WorkBuddy + Gitee:搭建AI可读的本地知识库同步与自动化体系

最初让我注意到这套组合,其实是被笔记同步折腾烦了。手上的知识库零散分布在本地文件夹、各种云笔记工具和聊天记录里,想查一个技术方案得来回切换好几个应用,更别提让AI帮忙归纳整理了——数据源散成一地,AI再强也等于没有眼睛。…

📰

ESP8266+MQTT接入阿里云物联网平台:从签名到上线的完整实战

1. 整体方案选型:用ESP8266MQTT连阿里云,图什么?1.1 ESP8266为什么够用做嵌入式联网项目,面临的第一道选择题就是:用什么芯片把设备拉上网。前几章我们用了STM32做主控,这一章要解决的是“上网”这件事。市…

📰

Codex CLI 安装与 CC Switch 配置:接入 DeepSeek 国内模型实战

1. 从零上手 Codex:这套组合拳到底解决了什么问题第一次听说 Codex 的人,十有八九会把它和某个具体的编辑器或者某个在线服务搞混。我刚开始接触的时候也一样,以为它就是个网页版的代码补全工具,点开就能用。实际折腾下来才发现&a…

📰

MR25H40CDF与STM32F412ZG的SPI接口实现工业级掉电数据存储方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

开发指南147-WebSocket-前后关联关系

前端动作后端触发/返回new SockJS(url)HandshakeInterceptor.beforeHandshake()client.activate()ChannelInterceptor.preSend(CONNECT)client.subscribe(...)preSend(SUBSCRIBE) 触发客户端 onConnect服务端回 CONNECTED客户端触发 onStompError服务端…

📰

JSP+Servlet学生成绩管理系统源码解析与实战避坑指南

简介:这是一套面向高校课程设计与Java Web入门进阶的完整学生成绩管理系统,基于JSP、Servlet、JDBC与MySQL实现,并引入MD5加密算法,覆盖学生、教师、管理员三类角色。学生端支持考勤管理、请假、选课、成绩查询与个人信息修改&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬