恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Java进阶篇之ConcurrentHashMap:把共享数据的更新放进原子操作

  • 首页
  • 资讯中心
  • /
  • Java进阶篇之ConcurrentHashMap:把共享数据的更新放进原子操作

相关资讯

RK3576 I3C实战指南:从DTS配置到HDR-DDR性能落地 2026/9/27 6:03:57
融合AI辅助MBTI性格测试的个性化健身小程序(DeepSeek AI 健身计划、AI 饮食方案、MBTI 四维性格测评、体征与营养记录、训练打卡日历、个人健身数据分析、AI方案人工审核、EChar) 2026/9/27 6:03:57
5G信令分析实战:从注册到切换的网优排障核心方法 2026/9/27 6:03:57

最新资讯

结构化任务规划方法论:Dillinger 仓库 plan-writing 技能详解与实战验证
深入 Tuta Mail 客户端代码库:架构、构建、测试与代码分块实战指南
《Windows Server 2022》 [2026年9月版 ] [简体/繁体/英文][官方ISO] 下载
杭州app网站设计速查手册:不会代码也能搞定SEO
AI论文工具怎么选?11款工具按任务对照,选对效率翻倍!
GitHub Desktop 发布说明写作规范与自动化流程解析

今日推荐

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本周热门

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Java进阶篇之ConcurrentHashMap:把共享数据的更新放进原子操作

发布时间:2026/9/27 6:03:57
Java进阶篇之ConcurrentHashMap:把共享数据的更新放进原子操作 上一篇用BlockingQueue把任务从生产者交给消费者。如果消费者需要统计每个接口处理了多少次请求就会遇到另一个问题多个线程同时修改同一张Map怎样才能保住每一次更新ConcurrentHashMap提供了并发访问能力。不过把HashMap换成它之后业务中的“读取、计算、写回”仍需要认真设计。这篇从计数场景出发梳理原子方法、可变对象和统计结果之间的关系。本文基于Java 21文档核对日期为2026年9月26日。示例只使用JDK标准库。一、容器安全与业务操作的边界先看一段容易出现的写法Integeroldcounts.getOrDefault(/orders,0);counts.put(/orders,old1);假设初始值为7两个线程都读取到7再分别写入8。最终只增加了一次。这里get和put各自能够安全执行但两次调用之间其他线程仍然可以进入。可以把业务要求写成一句话针对同一个key将旧值加一并保存作为一次完整更新完成。这时适合用mergecounts.merge(/orders,1,Integer::sum);key还没有映射时存入1已经存在时合并旧值和本次增量。不要把业务条件散落在多个独立调用中再期待容器自动把它们合成事务。二、先认识这张并发MapConcurrentHashMap实现了ConcurrentMap接口。日常使用可以分成三个层次读取映射、原子更新单个映射、观察整个容器。层次常见方法需要明确的边界读取get、containsKey读到的是一次访问的结果更新单个keyputIfAbsent、compute、merge适合把同一映射的判断与更新集中起来遍历与统计forEach、size并发修改期间不代表整张Map的固定快照它不接受null键或null值并发遍历采用弱一致性语义。遍历可以与更新同时进行不会因为并发修改直接抛出ConcurrentModificationException但也不能把结果当成同一时刻的完整快照。具体契约见Java 21的ConcurrentHashMap文档。本文聚焦公开API。老资料中常见的Segment分段锁讲法带有实现版本背景阅读源码时应先确认JDK版本避免把某一版实现结构当成接口保证。三、把一次业务更新交给一个方法图中的两张“1”任务卡面向同一个计数器。每张卡都完成一次合并计数从7走到8再走到9。图示表达的是同一个key的更新语义没有把Map画成一把锁住所有键的大锁。几个常用方法可以这样选需求方法例子没有映射时放入默认对象putIfAbsent注册一个已准备好的配置需要时才构造对象computeIfAbsent为某个分组创建计数器根据旧值重新计算compute依据当前数量决定新数量将增量合并到旧值merge累加接口调用次数值仍符合预期才替换replace(key, old, new)尝试推进单个状态值例如用compute表达有限库存扣减时可以在回调里统一检查旧值和计算新值。但“扣库存后写订单、再更新另一个key”已经超出一个映射的范围应交给合适的事务或整体同步机制设计。还要留意回调返回null的含义在compute或已有映射的merge重映射中null可以表示删除映射。对于计数示例回调明确返回整数避免无意触发删除语义。四、完整示例并发累计接口调用次数下面启动4个工作线程每个线程对同一路径累计1000次。主线程等待所有任务结束再读取最终结果。importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.CountDownLatch;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;publicclassConcurrentMapDemo{publicstaticvoidmain(String[]args)throwsException{ConcurrentHashMapString,IntegercountsnewConcurrentHashMap();CountDownLatchstartnewCountDownLatch(1);ListFuture?tasksnewArrayList();try(ExecutorServicepoolExecutors.newFixedThreadPool(4)){for(intworker0;worker4;worker){tasks.add(pool.submit(()-{try{start.await();for(inti0;i1000;i){counts.merge(/orders,1,Integer::sum);}}catch(InterruptedExceptione){Thread.currentThread().interrupt();thrownewIllegalStateException(e);}}));}start.countDown();for(Future?task:tasks){task.get();}}System.out.println(/orderscounts.get(/orders));System.out.println(keyscounts.size());}}保存为ConcurrentMapDemo.java使用JDK 21执行javac-encodingUTF-8 ConcurrentMapDemo.javajavaConcurrentMapDemo输出/orders4000 keys1CountDownLatch只负责统一放行Future.get负责等待任务结束并把任务异常交回主线程准确累加来自merge所表达的原子更新。三个机制各有职责。这里的size是在全部更新完成后读取的因此可以验证key数量。若更新仍在持续拿size作为是否允许下一次写入的严格判断条件就会引入新的竞争窗口。五、value里的对象也需要保护考虑下面的代码groups.computeIfAbsent(java,key-newArrayList()).add(article);即使groups本身是ConcurrentHashMap多个线程仍可能拿到同一个ArrayList并同时add。安全保存对象引用不等于对象内部的所有操作都具备并发安全性。可以根据访问模式使用并发集合、为对象提供同步方法或者以不可变值替换旧值。不要只检查容器类型还要沿着value继续检查共享状态。对于高频统计官方文档也给出了LongAdder配合computeIfAbsent的用法frequencies.computeIfAbsent(path,key-newLongAdder()).increment();这适合频繁累加、阶段性观察的统计业务。LongAdder.sum不提供并发更新期间的原子快照在没有并发更新时返回的合计值才是准确的。如果业务要求精确地基于当前值作出一次扣减决定应重新选择同步方案不能直接套用统计计数器。详见LongAdder.sum的官方说明。六、几个值得提前避开的坑回调保持短小。compute或merge回调适合局部计算不宜塞入远程调用、长时间等待或复杂的嵌套更新。耗时操作会扩大竞争影响异常处理也更难解释。多key约束单独设计。“A减少一份、B增加一份”需要整体保持约束。两次单key更新即使分别安全中间状态仍可能被观察到。可变key谨慎使用。作为键参与equals和hashCode的内容应保持稳定。若放入Map后改变这些字段后续查找可能无法按原预期定位。先用契约写正确再通过测量优化。本文没有比较不同实现的吞吐量。容量、key分布、读写比例和回调开销都会影响表现实际压测要贴近业务负载。七、 思维导图ConcurrentHashMap并发访问不接受null遍历弱一致性单key原子更新merge合并增量compute重新计算computeIfAbsent初始化业务边界多次调用存在间隙value仍需并发设计多key约束单独保护使用建议回调短小结束后核对最终统计八、总结总结要点原子更新应围绕具体业务动作组织。一次计数尽量写成一次merge避免把读取和写回分散成两个可被插入的步骤。共享对象需要逐层检查。ConcurrentHashMap保护映射关系value对象的修改、多key之间的约束以及跨系统操作仍需要各自的并发方案。统计与判断有不同要求。运行中的遍历适合观察严格决策需要明确一致性边界示例在任务全部结束后验证最终值结论也限定在这个场景内。后续预告下一篇继续Java进阶系列聊聊ReentrantLock看看显式锁如何配合tryLock、可中断等待和finally管理临界区。如果你觉得这篇文章对你有所帮助欢迎点赞、收藏、分享

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号