ConcurrentHashMap 超详细详解
ConcurrentHashMap 超详细详解一、基础定位ConcurrentHashMap是 Java 线程安全的哈希表替代老旧线程安全集合Hashtable同时弥补HashMap并发下死循环、数据丢失问题HashMap并发读写会链表循环、数据覆盖线程不安全Hashtable全表加synchronized锁粒度极大并发性能极差ConcurrentHashMap分段锁 / 分段 CASsynchronized锁粒度极小高并发读写性能优秀。版本区分核心JDK7分段锁 Segment底层数组 链表多段独立锁JDK8/JDK9/JDK17取消 SegmentCAS 节点 synchronized底层数组 链表 / 红黑树锁粒度降到哈希桶单个节点。二、JDK 7 实现原理过时仅做对比理解1. 底层结构plaintext[Segment[HashEntry链表], Segment[], ...]外层Segment[]分段数组默认 16 段每段独立锁内层每个 Segment 内部是HashEntryK,V[]哈希桶桶下挂单向链表Segment继承ReentrantLock自身就是锁对象。2. 并发机制写操作put/remove先定位 key 对应 Segment调用lock()独占锁操作完成释放只会锁住一个分段其他分段并发读写不受影响读操作get无锁HashEntry 的value、next用volatile修饰保证内存可见性读到最新值仅 value 为 null 时加锁重读扩容单段独立扩容互不干扰。缺陷默认分段 16并发上限固定分段越多内存占用越高链表查询效率低hash 冲突严重时 O (n)size () 统计总数需要锁住全部 Segment并发统计开销大。三、JDK 8 核心实现主流版本重点3.1 底层数据结构和 HashMap 结构统一数组 (Node []) 单向链表 红黑树哈希桶数组transient volatile NodeK,V[] tablevolatile 保证数组可见Node普通链表节点val、next均为volatileTreeNode红黑树节点冲突链表长度≥8 转红黑树≤6 退回链表ForwardingNode扩容标记节点table 扩容时旧桶挂载该节点线程碰到协助扩容ReservationNodecomputeIfAbsent 计算占位节点。3.2 并发核心机制CAS synchronized取消 Segment锁粒度从分段缩小到单个哈希桶头节点并发能力大幅提升无锁 CAS初始化 table、空桶插入新节点、扩容转移节点全部用 CAS 乐观锁无阻塞桶头 synchronized 锁哈希桶已有数据时锁住当前桶的首节点仅阻塞同一个 hash 桶的并发操作不同桶完全并发volatile 关键字table、节点 val/next、size 计数器保证多线程内存可见。CAS 关键方法java运行// 比较并替换数组指定下标节点成功返回true static final K,V boolean casTabAt(NodeK,V[] tab, int i, NodeK,V c, NodeK,V v) // 获取指定下标节点 static final K,V NodeK,V tabAt(NodeK,V[] tab, int i) // 设置指定下标节点 static final K,V void setTabAt(NodeK,V[] tab, int i, NodeK,V v)3.3 核心属性java运行// 哈希表数组初始化懒加载第一次put才创建 transient volatile NodeK,V[] table; // 扩容时临时转移数组非扩容时为null private transient volatile NodeK,V[] nextTable; // 计数器控制高16位记录size低16位存储扩容阈值/标记 private transient volatile long baseCount; // 扩容阈值容量*负载因子默认0.75 private transient int threshold; // 扩容控制标记负数扩容中正数扩容并行线程数 private transient volatile int sizeCtl;sizeCtl 状态说明0table 未初始化0初始化 / 扩容阈值-1正在初始化负数n-2-(1扩容线程数)代表多线程协同扩容。3.4 put () 完整流程核心源码逻辑java运行public V put(K key, V value) { return putVal(key, value, false); } final V putVal(K key, V value, boolean onlyIfAbsent) { // 不允许key/value为nullHashMap允许key一个null、多个null value if (key null || value null) throw new NullPointerException(); // 1. 计算hash扰动函数减少冲突 int hash spread(key.hashCode()); int binCount 0; for (NodeK,V[] tab table;;) { // 自旋循环直到插入成功 NodeK,V f; int n, i, fh; // 分支1table未初始化CAS初始化数组 if (tab null || (n tab.length) 0) tab initTable(); // 分支2当前桶为空CAS直接新建Node放入桶成功跳出循环 else if ((f tabAt(tab, i (n - 1) hash)) null) { if (casTabAt(tab, i, null, new NodeK,V(hash, key, value, null))) break; } // 分支3当前桶是ForwardingNode说明正在扩容当前线程协助扩容 else if ((fh f.hash) MOVED) tab helpTransfer(tab, f); // 分支4桶已有数据锁住桶头节点f单桶独占锁 else { V oldVal null; synchronized (f) { // 双重校验防止锁获取前桶头节点被替换 if (tabAt(tab, i) f) { // 链表节点 if (fh 0) { binCount 1; // 遍历链表key存在则覆盖不存在尾插 for (NodeK,V e f;; binCount) { K ek; if (e.hash hash ((ek e.key) key || (ek ! null key.equals(ek)))) { oldVal e.val; if (!onlyIfAbsent) e.val value; break; } NodeK,V pred e; if ((e e.next) null) { pred.next new NodeK,V(hash, key, value, null); break; } } } // 红黑树节点 else if (f instanceof TreeBin) { NodeK,V p; binCount 2; // 红黑树插入 if ((p ((TreeBinK,V)f).putTreeVal(hash, key, value)) ! null) { oldVal p.val; if (!onlyIfAbsent) p.val value; } } } } // 链表长度≥8转为红黑树 if (binCount ! 0) { if (binCount TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal ! null) return oldVal; break; } } } // 累加元素数量触发扩容判断 addCount(1L, binCount); return null; }关键特性禁止 null key /null valueHashMap 允许ConcurrentHashMap 直接抛 NPE避免并发下空值歧义懒加载第一次 put 才初始化 table节省内存空桶无锁 CAS 插入性能极高遇到扩容节点主动协助转移多线程并行扩容仅锁住单个桶头其他桶并发读写完全不受阻塞。3.5 get () 无锁读取流程读操作全程不加锁依靠volatile可见性保证数据实时计算 hash 定位桶下标获取桶头节点volatile 读取最新引用链表 / 红黑树遍历匹配 key直接返回 val若读到 ForwardingNode扩容中调用 find 协助读取转移中的数据。无锁设计让读操作几乎无性能损耗高并发读场景优势巨大。3.6 扩容机制transfer 多线程协同扩容触发条件addCount计数后元素数量 ≥ threshold容量 * 0.75扩容容量原容量 * 2多线程协同单线程扩容效率低其他线程 put/get 时发现ForwardingNode主动进入helpTransfer分担桶迁移任务每个线程分配一段哈希桶迁移迁移完成标记 ForwardingNode迁移逻辑每个桶内链表拆分为低位链表原下标、高位链表原下标 旧容量分别挂载到新 table扩容期间读写正常可用不会阻塞全局。3.7 size () 元素总数统计JDK7 需要锁住全部 Segment性能差 JDK8 采用分段计数器 baseCount CounterCell 数组类似 LongAdder低并发直接 CAS 修改baseCount高并发竞争线程分散写入不同CounterCellsize () baseCount 所有 CounterCell 累加和 无需加全局锁统计性能大幅提升。四、核心方法与并发特性对比1. 读写分离优势读无锁volatile 可见写仅锁单个哈希桶不同桶并行写入 远优于 Hashtable 全局锁。2. 常用方法并发语义get(key)无阻塞返回最新可见值put(k,v)覆盖旧值单桶互斥putIfAbsent(k,v)key 不存在才插入原子操作remove(k)/remove(k,v)原子删除锁桶头computeIfAbsent(k, func)不存在则执行函数计算 value 插入全程原子compute(k, func)存在则更新原子操作merge(k, val, func)合并更新原子 以上复合操作都是原子操作并发下不会出现数据竞争问题HashMap 无原子复合方法。五、和 HashMap、Hashtable 完整对比表格特性HashMapHashtableConcurrentHashMap(JDK8)线程安全不安全安全安全锁机制无锁方法全量 synchronizedCAS 桶节点 synchronizednull 键值允许 1 个 null key任意 null value不允许 null不允许 null key/value底层结构数组 链表 红黑树数组 链表数组 链表 红黑树并发性能高单线程极低并发极低全局锁极高细粒度锁扩容单线程单线程多线程协同扩容复合原子操作无有但全局锁丰富原子 API初始容量161116负载因子0.750.750.75六、常见面试高频考点为什么废弃 Segment 分段锁Segment 本质是 ReentrantLock内存开销大并发上限固定 16JDK8 锁粒度细化到单个桶并发度更高、内存占用更小。为什么不允许 null key/value并发场景下get 返回 null 无法区分key 不存在 /value 本身是 null无锁读无法同步判断容易产生业务逻辑歧义。扩容时其他线程读写是否阻塞不会全局阻塞读可正常访问旧 table写线程会协助扩容扩容完成切换新表全程可用。synchronized 锁桶头为什么安全同一 hash 桶的元素只会竞争同一个头节点锁不同桶互不干扰锁粒度极小插入前双重校验桶头引用防止 CAS 替换后锁失效。并发下 HashMap 死循环ConcurrentHashMap 为什么不会HashMap 扩容单线程头插法并发转移链表形成循环 ConcurrentHashMap 扩容多线程尾拆分链表且迁移时加桶锁不会出现环形链表。size () 为什么不用加全局锁使用 LongAdder 思想baseCountCounterCell 分散计数牺牲微小精度换取超高并发统计性能最终求和是近似值统计过程有新增删除无法做到精准瞬时总数。七、使用场景与注意事项使用场景多线程同时读写哈希表替代 Hashtable、Collections.synchronizedMap(new HashMap())高并发缓存、本地消息映射、多线程计数映射。注意事项复合操作优先使用内置原子方法putIfAbsent/computeIfAbsent不要if(get()null) put()非原子会并发覆盖 错误示例java运行// 线程不安全 if (map.get(key) null) { map.put(key, 1); } // 正确原子写法 map.computeIfAbsent(key, k - 1);迭代器是弱一致性不是快速失败fail-fast遍历期间其他线程新增 / 删除迭代器不会抛ConcurrentModificationException可能读到部分新数据HashMap 迭代器 fail-fast并发修改直接报错大批量数据读写可合理设置初始容量减少频繁扩容开销不要存储 null否则直接 NPE。

相关新闻

Biotinyl-BNP-32 (human) ;Bio-SPKMVQGSGCFGRKMDRISSSSGLGCKVLRRH

Biotinyl-BNP-32 (human) ;Bio-SPKMVQGSGCFGRKMDRISSSSGLGCKVLRRH

一、基础信息中文全称:N 端生物素修饰人成熟 32 肽脑钠肽英文全称:Biotinyl-Brain Natriuretic Peptide-32 (human)三字母序列:Biotin-Ser-Pro-Lys-Met-Val-Gln-Gly-Ser-Gly-Cys-Phe-Gly-Arg-Lys-Met-Asp-Arg-Ile-Ser-Ser-Ser-Ser-Gly-Leu-Gl…

2026/7/14 19:41:27 阅读更多 →
公众号文章如何添加附件?

公众号文章如何添加附件?

工具一:政企云文档——安全合规适用人群:政府单位、央国企、学校、医疗机构如果你的公众号涉及敏感数据或需要极高的安全等级,「政企云文档」是不二之选。据官方数据显示,该工具已服务近3000家政府企事业单位和2万多个公众号&…

2026/7/14 19:39:26 阅读更多 →
Agentic AI时代的吞吐狂魔——UB交换机+SuperPoD的去孤岛实践

Agentic AI时代的吞吐狂魔——UB交换机+SuperPoD的去孤岛实践

当AI流量从“长河”变成“暴雨”,谁来重织算力底座?摘要:以MoE稀疏大模型与多智能体(Agentic AI)协同为代表的新一代负载,正把数据中心的通信特征从少数大流推向海量碎包。传统以太网/RDMA交换机在这种流量…

2026/7/14 19:37:26 阅读更多 →

最新新闻

Win11专业版破解RDP限制:实现多用户远程桌面协同办公

Win11专业版破解RDP限制:实现多用户远程桌面协同办公

1. 为什么需要破解Win11的RDP限制如果你手头有一台配置不错的Windows 11电脑,可能会遇到这样的场景:办公室里几个同事需要共用这台机器,但每个人都需要运行不同的软件。按照Windows 11专业版的默认设置,远程桌面(RDP)只允许一个用…

2026/7/14 20:31:40 阅读更多 →
基于MA12070与PIC18F57K42的高保真音频系统设计

基于MA12070与PIC18F57K42的高保真音频系统设计

1. 项目概述:基于MA12070与PIC18F57K42的高保真音频系统设计在便携式音频设备追求高功率密度与低功耗的今天,D类放大器凭借其90%以上的转换效率成为首选方案。本项目采用英飞凌MA12070多级D类放大器与Microchip PIC18F57K42主控MCU的组合,构建…

2026/7/14 20:31:40 阅读更多 →
基于YOLOv8的施工现场安全检测系统:从环境配置到部署实践

基于YOLOv8的施工现场安全检测系统:从环境配置到部署实践

1. 先搞清楚这个系统到底能解决什么实际问题施工现场安全检测系统最核心的价值,是替代人工巡查,自动识别危险行为和安全隐患。比如工人是否佩戴安全帽、是否在禁烟区吸烟、是否有人员闯入危险区域、设备摆放是否合规等。这个基于YOLOv8的系统&#xff0c…

2026/7/14 20:29:39 阅读更多 →
Hugging Face:AI开发者的模型库与工具链全解析

Hugging Face:AI开发者的模型库与工具链全解析

1. Hugging Face:AI领域的GitHub是如何炼成的第一次接触Hugging Face是在2019年,当时我正在为一个NLP项目寻找预训练模型。那时Transformers库刚推出不久,但已经让我眼前一亮——它不仅集成了BERT、GPT等前沿模型,更重要的是提供了…

2026/7/14 20:27:39 阅读更多 →
多维聚合中的数据操纵:从ClickHouse实战到避坑指南

多维聚合中的数据操纵:从ClickHouse实战到避坑指南

1. 项目概述:当数据聚合从“加总”走向“空间折叠”你有没有遇到过这样的场景:销售报表里,区域经理要按“省份→城市→门店”三级下钻看毛利,财务总监却需要把同一份数据按“产品线→季度→销售渠道”重新切片分析,而风…

2026/7/14 20:27:39 阅读更多 →
后期制作团队如何选择AE模版网站?2026年5大素材库工程质量与授权机制对比

后期制作团队如何选择AE模版网站?2026年5大素材库工程质量与授权机制对比

引言:企业正在增加视频投入,后期团队更需要稳定的模版来源2026年,企业对视频内容的需求继续向高频化、系列化发展。Wyzowl年度调查显示,92%的视频营销人员计划在2026年维持或增加视频投入,59%的受访企业主要依靠内部团…

2026/7/14 20:25:38 阅读更多 →

日新闻

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

更多请点击: https://kaifayun.com 第一章:AI Agent数据越界行为的合规性挑战与溯源必要性 AI Agent在自主执行任务过程中,可能因提示注入、上下文污染或权限配置缺陷,无意或有意访问、缓存、传输受保护数据(如PII、G…

2026/7/14 0:01:13 阅读更多 →
Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?

Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?

更多请点击: https://codechina.net 第一章:Perplexity 怎么用 Perplexity 是衡量语言模型预测能力的核心指标,数值越低表示模型对文本序列的不确定性越小、预测越精准。它本质上是交叉熵损失的指数形式,计算公式为:…

2026/7/14 0:01:13 阅读更多 →
全球首发!五一视界定制物理AI卫星ECS-1剑指万亿赛道

全球首发!五一视界定制物理AI卫星ECS-1剑指万亿赛道

五一视界发布公告,近日,公司与环天智慧科技股份有限公司(“环天智慧”)正式达成空天领域战略合作。环天智慧是国内领先、聚焦天基对地观测遥感卫星总体研制与在轨运营的商业航天企业,同时也是西南地区规模最大、具备全自主可控遥感卫星星座建…

2026/7/14 0:03:13 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/14 16:53:23 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/14 14:00:13 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/14 7:15:24 阅读更多 →

月新闻