当前位置: 首页 > news >正文

深入图解 ConcurrentHashMap 底层实现:从 JDK1.7 到 1.8 的史诗级蜕变

导语
在 Java 面试中,如果有哪一个集合类能霸占 80% 的出场率,那绝对非ConcurrentHashMap莫属。大家都知道HashMap线程不安全,HashTable性能又太差。为了兼顾“性能”和“安全”,ConcurrentHashMap站了出来。
但这并不是最要命的,让无数开发者头疼的地方在于:从 JDK 1.7 到 JDK 1.8,它的底层数据结构发生了一次“史诗级”的颠覆。本篇文章,我们将拨开源码的迷雾,用最通俗的语言,带你彻底搞懂这两个版本的底层实现逻辑。


🎯 一、 前置知识:为什么要有 ConcurrentHashMap?

在单线程环境下,HashMap是无敌的。但是在多线程并发写入时,HashMap会出现不可预知的安全问题(特别是在 JDK 1.7 中,多线程扩容甚至会导致链表形成“死环”,让 CPU 飙升到 100%)。

如果为了安全直接换成HashTable,它粗暴地给整个方法加上了synchronized(相当于独占锁)。只要有一个线程在操作,别的线程全都在门外干等,性能极其低下。

为了解决这个问题,ConcurrentHashMap诞生了,它的终极目标就是:尽可能地缩小加锁的范围,让各个线程互不干扰地并发工作。


🏗️ 二、 JDK 1.7 的实现:经典经典的“分段锁”设计

在 JDK 1.7 时期,ConcurrentHashMap 的核心设计思想非常明确,叫做:分段锁(Segment)

1. 核心底层结构

它的底层采用的是:Segment 数组+HashEntry 数组+链表的嵌套结构。

  • 外层结构 (Segment 数组):它首先将整个大 Map 拆分成了很多个小的子 Map,这些子 Map 被称为Segment。默认情况下有 16 个 Segment。
  • 内层结构 (HashEntry 数组 + 链表):每一个Segment里面,本质上就是一个小型的HashMap(数组+链表)。

2. 它是如何工作的?

当你想要向 Map 中 put 一个键值对时:

  1. 先做一次 Hash,定位到它属于哪一个Segment
  2. 再去获取这个Segment的锁。
  3. 获取到锁之后,再做一次 Hash,定位到内部的HashEntry数组的具体位置,挂到链表上。

💡小白通俗易懂解释
JDK 1.7 的 ConcurrentHashMap 就像是一个拥有16 个独立房间的大仓库
HashTable是在仓库大门上挂了一把大锁,一次只能进去一个人。
ConcurrentHashMap 1.7是在大门不设阻拦,给16 个房间的门上分别挂了一把锁。只要你们不去同一个房间放东西,大家就可以同时进去干活,理论上最高能支持 16 个人(线程)同时操作,互不影响!


🚀 三、 JDK 1.8 的蜕变:抛弃 Segment,向“数组+链表+红黑树”进化

虽然分段锁的设计很巧妙,但是 JDK 开发团队认为它还不够极致。在 JDK 1.8 中,整个架构被全面推翻重写!

1. 为什么抛弃了 Segment?

  • 并发度受限:Segment 的数量一旦初始化就不能更改(默认 16),这意味着哪怕后面你的数据量达到百万级别,最高并发度依然只有 16。
  • 内存开销大:外层 Segment 数组使得层级变深,每一个 Segment 都要维护一套各种指标参数,白白吃掉了很多堆内存。
  • 查询效率不够高:极端情况下(发生严重的 Hash 冲突),所有的元素都挂在同一个长长的单向链表上,导致查询速度从O(1)退化成非常慢的O(N)

2. 1.8 的核心底层结构

抛弃了臃肿的Segment,JDK 1.8 把结构重新拍扁,直接回归了原汁原味的HashMap风格,采用了:
Node 数组+单向链表+红黑树

  • 扁平化:直接由一个巨大的Node[] table撑起局面。
  • 引入红黑树:这是最大的杀招。当某一层位置上的链表长度超过 8 且数组总长度超过 64时,链表会扭身一变,转化成极速的“红黑树”。

💡小白通俗易懂解释
JDK 1.8 直接把 16 个小房间的隔离墙给拆了,变成了一个巨大的露天广场(Node数组),上面有无数个摊位。
如果大家都去不同的摊位,那是毫无阻碍的并发。
但如果某一个摊位生意太火爆,排队的人连成了一条长龙(链表太长),老板就会直接造一台高速电梯(红黑树),让你找货的速度从“一层层爬楼梯”变成了“极速直达”(查询复杂度从 O(N) 变成了 O(logN))。


📊 四、 总结:从 1.7 到 1.8 的三大演进对比

维度JDK 1.7JDK 1.8核心演进点与优势
整体数据结构Segment数组 + HashEntry数组 + 链表Node数组 + 链表 + 红黑树结构被拍扁,取消了 Segment 的包裹,内存占用大幅下降。
极限查询性能链表退化,最差 O(N)引入红黑树,最差 O(logN)解决了 Hash 严重冲突时,链表无限长导致的查询灾难。
最高并发粒度受限于 Segment 数量(默认 16)受限于 Node 数组的长度 (极其庞大)彻底解放了并发能力的上限,数组有多长,就能支持多大的并发量。

下篇预告:我们在本文搞懂了它在不同时代下的数据结构模型。但在彻底取消了 Segment 分段锁的 1.8 中,它是究竟如何保证多线程安全的呢?请移步本专栏姊妹篇《揭秘 ConcurrentHashMap 并发安全的底层黑科技》。

http://www.jsqmd.com/news/536420/

相关文章:

  • 从爬取到预测:基于Python的招聘数据全链路分析与可视化实战(含薪资预测模型)
  • ST25DV64KC动态NFC标签Arduino驱动库详解
  • OpenClaw报错排查大全:GLM-4.7-Flash接口连接失败解决方案
  • 西城区三字堂硬笔书法
  • 4大突破:面向全场景的聊天应用UI设计方案
  • 解决 cl.exe 构建和调试活动文件仅在 VS Code 从 Developer Command Prompt 中运行时才可用的效率优化方案
  • OpenClaw性能白皮书:Qwen3.5-9B在不同任务类型的基准测试
  • OpenClaw养虾逻辑:目的决定架构,用途决定安全,角色决定权限
  • node-sass 构建失败问题解决方法
  • OpenClaw社区资源利用:Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF相关插件与技能推荐
  • OpenClaw负载监控:QwQ-32B长时间运行的稳定性保障
  • 【完整源码+数据集+部署教程】导盲犬辅助物体检测系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]
  • CF1398D Colored Rectangles
  • ATtiny85极简Si5351 CLK0驱动:100–150MHz单频点时钟配置
  • EPO蛋白在肾性贫血诊断中的应用研究
  • 数据密集型文件的高效压缩技术:从原理到企业级解决方案
  • 基于cosyvoice 2声码器的实时语音合成实战:从选型到生产环境部署
  • 《QGIS快速入门与应用基础》238:添加指北针工具
  • 嵌入式C语言面试核心问题与实战技巧
  • ChatGPT API限额优化实战:如何突破并发限制与成本控制
  • 如何突破高频数据处理瓶颈?Qlib订单簿引擎实战指南
  • 杰理之 检查触摸数据【篇】
  • 一键部署生产力:星图平台OpenClaw+Qwen3.5-9B体验
  • 从带宽爆炸到95%成本下降:C#上位机+Azure IoT Edge 仓储AGV边缘计算全流程落地
  • ⋐ 13-2 ⋑ 软考高项 | 第18章:项目绩效域 [ 下 ]
  • CF2103A Common Multiple
  • ChatGPT API路由错误(409)排查指南:从invalid client到稳定集成的解决方案
  • 金蝶云星空与每刻报销系统对接方案:精准数据处理
  • Chatbot DeepResearch 技术解析:从架构设计到生产环境优化
  • OpenClaw+nanobot自动化写作:Qwen3-4B模型内容生成实测