Java ConcurrentHashMap 实战:computeIfAbsent 重入死锁、原子累加与 size 为什么不准

发布时间:2026/10/7 18:02:22

Java ConcurrentHashMap 实战:computeIfAbsent 重入死锁、原子累加与 size 为什么不准 Java ConcurrentHashMap 实战:computeIfAbsent 重入死锁、原子累加与 size 为什么不准很多人把ConcurrentHashMap当成「加了锁的 HashMap」,以为随便用都线程安全。实际上它只保证单个方法调用的原子性,一旦你把「读—改—写」拆成几步,或者在computeIfAbsent里再动这个 map,坑就来了。这篇讲三个真实踩过的问题。陷阱一:先 get 再 put 不是原子操作统计词频最容易写出这种代码:// 错误:get 和 put 之间可能被其他线程插队,计数丢失ConcurrentHashMapString,IntegermapnewConcurrentHashMap();Integercmap.get(word);map.put(word,cnull?1:c1);get和put各自线程安全,但组合起来有竞态:两个线程同时读到 5,各自 1 写回 6,少算一次。ConcurrentHashMap帮不了你,因为它根本不知道这两次调用要绑在一起。正确做法是用一次原子调用完成累加。计数场景首选merge:// 正确:merge 内部对该 key 加锁,读改写是原子的map.merge(word,1,Integer::sum);或者用getOrDefault是只读的、compute系列是原子的,别把它们和裸put混着用。陷阱二:computeIfAbsent 里再碰同一个 map 死锁/异常computeIfAbsent会对当前 key 所在的桶加锁,然后执行你的 lambda。如果 lambda 里又去写同一个 map,轻则抛异常,重则活锁。经典翻车:递归建缓存。// 危险:mappingFunction 里又调了 computeIfAbsentmap.computeIfAbsent(a,k-{map.computeIfAbsent(b,k2-compute(k2));// 可能死锁/IllegalStateExceptionreturncompute(k);});Java 9 对这种自引用会抛IllegalStateException: Recursive update,更早的版本可能直接卡死。修法是把「计算」和「放入」拆开,计算过程不碰 map:// 先算好,再原子放入Valuevmap.get(key);if(vnull){ValuecomputedexpensiveCompute(key);// 纯计算,不碰 mapvmap.putIfAbsent(key,computed);// 已存在就用别人放的if(vnull)vcomputed;}putIfAbsent返回旧值:返回 null 说明是你放进去的,非 null 说明别人先放了,用它的即可,天然去重。陷阱三:size() 是估算值,别拿去做精确判断高并发下size()/isEmpty()返回的是某一瞬间的近似值,不保证和「此刻真实元素数」一致。下面这种「满了就停」的逻辑会出错:// 不可靠:size() 在并发写入时可能读到旧值if(map.size()MAX)return;// 可能已经超了,也可能还没到map.put(key,val);如果你需要「容量上限」这种强一致语义,ConcurrentHashMap本身不提供,应该用带计数的原子变量或专门的限流结构。size()只适合做监控、日志这类容忍误差的场景。顺带一提:原子累加用 LongAdder 更快如果只是全局计数(不是按 key 分组),别用ConcurrentHashMap存一个 key,直接上LongAdder,高并发下比AtomicLong少了 CAS 自旋冲突:LongAddercounternewLongAdder();counter.increment();// 内部分段累加,竞争小longtotalcounter.sum();小结ConcurrentHashMap只保证单次方法调用原子,get之后再put会丢更新;计数用merge(key, 1, Integer::sum)。computeIfAbsent的 lambda 里绝不能再写同一个 map,Java 9 会抛Recursive update;拆成「先算后 putIfAbsent」。size()/isEmpty()是估算值,不能用来做精确的容量判断。记忆点:读改写要合并成一次原子调用,计算逻辑别塞进 compute 的 lambda 里。
延伸阅读

更多相关文章

2026/10/7 13:49:46

信号与系统考研强化指南:吴大正教材核心考点与专题突破

在考研复习的冲刺阶段,信号与系统这门课常常让很多同学感到“又爱又恨”。爱的是它的逻辑性强,体系完整;恨的是概念抽象,题型多变,尤其是面对吴大正老师这本经典教材,如何从厚厚的书本中提炼出核心考点&…

2026/10/8 0:17:18

AI代码生成如何实现生成即规范:CleanCode编程标准落地实践

1. 为什么“生成即规范”是个被低估的刚需先说一个我观察了很久的现象:绝大多数团队引入AI代码生成工具之后,代码产出速度确实上去了,但代码评审的负担反而更重了。原因很简单——AI生成的代码能跑,但不一定能看。变量命名随缘、函…

2026/10/8 0:17:18

NUC 16 Pro本地大模型部署实战:安全、合规、可落地的AI工作站方案

1. 这不是“玩具”,是真正能干活的本地AI工作站“本地跑大模型,数据不用出内网”——这句话在2024年已经不是技术极客的自嗨,而是金融、医疗、政务、研发类企业真实存在的刚需。我上个月刚帮一家三甲医院信息科部署完一套基于NUC 16 Pro的本地…

2026/10/8 0:17:18

OpenMontage:面向视频生产的开源Agentic架构系统

1. OpenMontage 是什么:一个被严重误读的开源视频生产代理系统OpenMontage 这个名字一出现,很多人第一反应是“又一个 Montage 风格的视频剪辑工具”,甚至下意识联想到 Adobe Premiere 的蒙太奇时间线、Final Cut Pro 的磁性时间线&#xff0…

2026/10/8 0:17:18

Loongarch单周期CPU设计实战:20条指令深度解析

1. 这不是“搭积木”,是亲手捏出一颗能呼吸的CPU心脏你手头这份“CPU设计实战:Loongarch版 lab6——20条指令单周期CPU”,绝不是Logisim里拖几个寄存器、连几根线、点个仿真就完事的课程作业。它是一次对计算机底层血脉的解剖与重建——你要亲…

2026/10/8 0:12:18

Flutter鸿蒙开发实践:校园打印店打卡应用落地复盘

这几年校园场景里的应用需求越来越多,打印店打卡就是其中一个典型:学生到店取文件要确认订单、商家要核销打印任务、管理员还要统计使用量。我之前做过几版纯原生实现,安卓一套、iOS一套、鸿蒙再一套,维护成本直接失控。后来换成 …

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/7 8:18:33

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

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

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑