【避坑指南】ConcurrentHashMap 并发操作的致命陷阱
注本文是笔者在学习【极客时间】业务开发常见错误过程中整理记载的个人学习和思考笔记在高并发编程中ConcurrentHashMap 因线程安全特性被广泛使用但很多开发者误以为「用了 ConcurrentHashMap 就万事大吉」却忽略了复合操作的原子性问题。本文通过一个真实的代码案例拆解 ConcurrentHashMap 的常见误用场景并给出正确的解决方案。一、案例场景并发填充 ConcurrentHashMap先看这段 Spring Boot 控制器代码核心逻辑是初始化一个包含 900 个元素的 ConcurrentHashMap然后启动 10 个线程并发补充元素目标是让最终元素总数达到 1000。1. 问题代码wrong 接口GetMapping(wrong/concurrenthashmap)publicStringwrong()throwsInterruptedException{// 初始化900个元素ConcurrentHashMapString,LongconcurrentHashMapgetData(ITEM_COUNT-100);log.info(init size:{},concurrentHashMap.size());ForkJoinPoolforkJoinPoolnewForkJoinPool(THREAD_COUNT);// 10个线程并发补充元素forkJoinPool.execute(()-IntStream.rangeClosed(1,10).parallel().forEach(i-{// 致命问题计算缺口 补充元素 非原子操作intgapITEM_COUNT-concurrentHashMap.size();log.info(线程{} - gap size:{},Thread.currentThread().getName(),gap);concurrentHashMap.putAll(getData(gap));}));forkJoinPool.shutdown();forkJoinPool.awaitTermination(1,TimeUnit.HOURS);log.info(finish size:{},concurrentHashMap.size());// 结果远大于1000returnOK;}2. 运行结果预期最终 size1000但实际运行结果往往是 1500、1800 甚至更高完全超出预期。二、问题根源复合操作缺乏原子性ConcurrentHashMap 仅保证单个方法如 put、get、size的线程安全但多个方法组合的复合操作不具备原子性。这个案例中核心问题出在两步操作1. 非原子的「计算缺口 补充元素」// 步骤1计算需要补充的元素数量intgapITEM_COUNT-concurrentHashMap.size();// 步骤2补充gap个元素concurrentHashMap.putAll(getData(gap));线程 A 执行gap 1000 - 900 100准备补充 100 个元素线程 B 同时执行gap 1000 - 900 100也准备补充 100 个元素线程 A 先完成 putAllMap 大小变为 1000线程 B 仍按之前计算的 gap100 执行 putAll最终 Map 大小变为 110010 个线程重复此过程最终 size 远大于 1000。2. 对 ConcurrentHashMap 的认知误区很多开发者误以为「ConcurrentHashMap 是线程安全的所以所有操作都安全」但事实是ConcurrentHashMap 仅保证单个方法调用的原子性如 put 时不会出现数据覆盖跨方法的复合操作如「读 size → 计算 → 写数据」必须手动保证原子性。三、正确解决方案correct 接口核心思路给「计算缺口 补充元素」的复合操作加锁确保同一时间只有一个线程执行该逻辑。GetMapping(correct/concurrenthashmap)publicStringcorrect()throwsInterruptedException{ConcurrentHashMapString,LongconcurrentHashMapgetData(ITEM_COUNT-100);log.info(init size:{},concurrentHashMap.size());ForkJoinPoolforkJoinPoolnewForkJoinPool(THREAD_COUNT);forkJoinPool.execute(()-IntStream.rangeClosed(1,10).parallel().forEach(i-{// 加锁保证复合操作的原子性synchronized(concurrentHashMap){intgapITEM_COUNT-concurrentHashMap.size();log.info(线程{} - gap size:{},Thread.currentThread().getName(),gap);// 增加边界判断避免gap为负数时添加空数据if(gap0){concurrentHashMap.putAll(getData(gap));}}}));forkJoinPool.shutdown();forkJoinPool.awaitTermination(1,TimeUnit.HOURS);log.info(finish size:{},concurrentHashMap.size());// 稳定为1000returnOK;}关键优化点加锁范围精准仅对「计算 gap putAll」的复合操作加锁避免锁范围过大影响性能增加边界判断gap ≤ 0 时不再执行 putAll避免无效操作锁对象选择直接使用 ConcurrentHashMap 实例作为锁对象也可自定义专用锁。四、ConcurrentHashMap 避坑指南1. 核心原则区分「单个操作」和「复合操作」操作类型是否线程安全示例单个方法调用安全map.put(k, v)、map.get(k)复合操作不安全先 get 再 put、先 size 再 put2. 常见误用场景 解决方案误用场景错误原因正确方案先判断 key 是否存在再 put 数据判断和 put 非原子操作使用putIfAbsent(k, v)方法先读 size再根据 size 写数据读和写非原子操作加锁synchronized/Lock循环遍历 Map 同时修改元素遍历和修改竞态条件使用迭代器的原子操作或加锁遍历多个 put 操作需保证整体成功单个 put 安全但整体不安全加锁或使用事务如数据库兜底3. 性能优化建议加锁时最小化锁范围仅锁定复合操作的核心逻辑避免整个方法加锁优先使用 ConcurrentHashMap 提供的原子方法如putIfAbsent、compute、merge等减少手动加锁高并发场景下可考虑分段锁/分片处理降低锁竞争。4. 替代方案按需选择如果业务允许最终一致性可使用 AtomicLong 统计数量单独维护 MapJDK 1.8 可使用LongAdder替代 AtomicLong 统计计数性能更高极端高并发场景可考虑使用 Disruptor 等无锁框架。五、总结ConcurrentHashMap 是线程安全的但它保护的是「单个方法」而非「业务逻辑」。使用时必须牢记复合操作必须手动保证原子性加锁或使用内置原子方法避免认知误区线程安全容器 ≠ 线程安全业务逻辑锁范围越小越好在保证线程安全的前提下尽可能减少锁竞争。希望本文能帮你避开 ConcurrentHashMap 的常见陷阱写出更健壮的高并发代码

相关新闻

【RTX4070】12g显存 ComfyUI AI 视频 (T2V/I2V) 避坑与实战指南

【RTX4070】12g显存 ComfyUI AI 视频 (T2V/I2V) 避坑与实战指南

进阶之路:资深玩家的 ComfyUI AI 视频 (T2V/I2V) 避坑与实战指南 对于习惯了代码逻辑的开发者来说,初入 ComfyUI 的感觉就像是接手了一个没有说明文档的开源微服务架构。节点满天飞、连线如乱麻、动不动就爆显存(OOM)或者产出“电…

2026/5/17 12:55:38 阅读更多 →
ssm+java2026年毕设社区少年儿童读物共享系统【源码+论文】

ssm+java2026年毕设社区少年儿童读物共享系统【源码+论文】

本系统(程序源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、选题背景关于图书管理与分享问题的研究,现有研究主要以传统图书馆管理系统和数字化阅读平台为主,专门针对社交化…

2026/7/3 19:36:42 阅读更多 →
ConcurrentNativeQueue<T>:一个使用 .NET 实现的零 GC 压力的无锁 MPSC 原生队列

ConcurrentNativeQueue<T>:一个使用 .NET 实现的零 GC 压力的无锁 MPSC 原生队列

ConcurrentNativeQueue<T>:一个使用 .NET 实现的零 GC 压力的无锁 MPSC 原生队列 一、为什么要造这个轮子 .NET 提供了 ConcurrentQueue<T> 和 Channel<T> 两种开箱即用的并发队列。对大多数业务场景,它们已经足够好。但在以下场景中,它们的底层设计决策…

2026/5/17 9:00:24 阅读更多 →

最新新闻

status-go终极指南:构建去中心化社交应用的完整Go后端解决方案

status-go终极指南:构建去中心化社交应用的完整Go后端解决方案

status-go终极指南&#xff1a;构建去中心化社交应用的完整Go后端解决方案 【免费下载链接】status-go The "backend" library for Status Apps 项目地址: https://gitcode.com/gh_mirrors/st/status-go 想要快速构建去中心化社交应用&#xff1f;&#x1f68…

2026/7/4 7:16:59 阅读更多 →
为什么选择Slash?对比原生NSAttributedString,这款富文本工具到底强在哪里?

为什么选择Slash?对比原生NSAttributedString,这款富文本工具到底强在哪里?

为什么选择Slash&#xff1f;对比原生NSAttributedString&#xff0c;这款富文本工具到底强在哪里&#xff1f; 【免费下载链接】Slash A better way to create attributed strings 项目地址: https://gitcode.com/gh_mirrors/slash/Slash 如果你是iOS或macOS开发者&…

2026/7/4 7:16:59 阅读更多 →
如何将Statsig Status Page部署到自定义域名:完整教程

如何将Statsig Status Page部署到自定义域名:完整教程

如何将Statsig Status Page部署到自定义域名&#xff1a;完整教程 【免费下载链接】statuspage A simple, zero-dependency, pure js/html status page based on GitHub Pages and Actions. 项目地址: https://gitcode.com/gh_mirrors/sta/statuspage Statsig Status Pa…

2026/7/4 7:14:59 阅读更多 →
CANN/PID批量滚动评分算法

CANN/PID批量滚动评分算法

PidFopdtBatchRolloutScore Algorithm 【免费下载链接】mat-chem-sim-pred 面向工业领域&#xff0c;聚焦计算仿真、预测两大核心场景&#xff0c;构建面向流程工业"机理数据"双轮驱动的领域计算层&#xff0c;推动AI for Science在材料化学领域的深度应用。 项目地…

2026/7/4 7:14:59 阅读更多 →
NCSN项目结构全解析:从配置文件到四大Runner类的使用指南

NCSN项目结构全解析:从配置文件到四大Runner类的使用指南

NCSN项目结构全解析&#xff1a;从配置文件到四大Runner类的使用指南 【免费下载链接】ncsn Noise Conditional Score Networks (NeurIPS 2019, Oral) 项目地址: https://gitcode.com/gh_mirrors/nc/ncsn Noise Conditional Score Networks&#xff08;NCSN&#xff09;…

2026/7/4 7:14:59 阅读更多 →
Panel Colorizer与Plasma Manager集成:NixOS环境下的最佳实践

Panel Colorizer与Plasma Manager集成:NixOS环境下的最佳实践

Panel Colorizer与Plasma Manager集成&#xff1a;NixOS环境下的最佳实践 【免费下载链接】plasma-panel-colorizer Latte-Dock and WM status bar customization for the KDE Plasma panels 项目地址: https://gitcode.com/gh_mirrors/pl/plasma-panel-colorizer 想要为…

2026/7/4 7:12:58 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布&#xff0c;这是一个关键的安全修复版本&#xff0c;修复了多个方面的问题&#xff0c;还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出&#xff0c;mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南&#xff1a;使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL&#xff08;Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器&#xff0c;与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻