深入浅出ConCurrentHashMap(一)
ConcurrentHashMap 是 Java 并发包 (java.util.concurrent) 中的一种线程安全的哈希表实现。HashMap 在多线程环境下扩容会出现 CPU 接近 100% 的情况因为 HashMap 并不是线程安全的我们可以通过 Collections 的Map synchronizedMap(Map m)将 HashMap 包装成一个线程安全的 map。比如 SynchronzedMap 的 put 方法源码就是加锁过的public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} }不过这并不是最优雅的方式。相对于 HashMapConcurrentHashMap 就是线程安全的 map其中利用了锁分段的思想大大提高了并发的效率。1.8 版本舍弃了 segment并且使用了大量的 synchronized以及 CAS 无锁操作以保证 ConcurrentHashMap 的线程安全性。为什么不用 ReentrantLock 而是 synchronzied 呢实际上synchronzied 做了很多的优化这个我们前面也讲过了包括偏向锁、轻量级锁、重量级锁可以依次向上升级锁状态因此synchronized 相较于 ReentrantLock 的性能其实差不多甚至在某些情况更优。ConcurrentHashMap 的变化ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 中有一些区别。JDK 1.7ConcurrentHashMap 在 JDK 1.7 中提供了一种粒度更细的加锁机制这种机制叫分段锁「Lock Striping」。整个哈希表被分为多个段每个段都独立锁定。读取操作不需要锁写入操作仅锁定相关的段。这减小了锁冲突的几率从而提高了并发性能。这种机制的优点在并发环境下将实现更高的吞吐量而在单线程环境下只损失非常小的性能。可以这样理解分段锁就是将数据分段对每一段数据分配一把锁。当一个线程占用锁访问其中一个段数据的时候其他段的数据也能被其他线程访问。有些方法需要跨段比如size()、isEmpty()、containsValue()它们可能需要锁定整个表而不仅仅是某个段这需要按顺序锁定所有段操作完后再按顺序释放所有段的锁。如下图ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组构成的。Segment 是一种可重入的锁 ReentrantLockHashEntry 则用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组Segment 的结构和 HashMap 类似是一种数组和链表结构一个 Segment 里包含一个 HashEntry 数组每个 HashEntry 是一个链表结构的元素每个 Segment 守护着一个 HashEntry 数组里的元素当对 HashEntry 数组的数据进行修改时必须首先获得它对应的 Segment 锁。单一的 Segment 结构如下像这样的 Segment 对象在 ConcurrentHashMap 集合中有 2 的 N 次方个共同保存在一个名为 segments 的数组当中。 因此整个 ConcurrentHashMap 的结构如下可以说ConcurrentHashMap 是一个二级哈希表。在一个总的哈希表下面有若干个子哈希表。Case1不同 Segment 的并发写入可以并发执行Case2同一 Segment 的一写一读可以并发执行Case3同一 Segment 的并发写入Segment 的写入是需要上锁的因此对同一 Segment 的并发写入会被阻塞。由此可见ConcurrentHashMap 中每个 Segment 各自持有一把锁。在保证线程安全的同时降低了锁的粒度让并发操作效率更高。ConcurrentHashMap 读写过程如下get 方法为输入的 Key 做 Hash 运算得到 hash 值。通过 hash 值定位到对应的 Segment 对象再次通过 hash 值定位到 Segment 当中数组的具体位置。put 方法为输入的 Key 做 Hash 运算得到 hash 值。通过 hash 值定位到对应的 Segment 对象获取可重入锁再次通过 hash 值定位到 Segment 当中数组的具体位置。插入或覆盖 HashEntry 对象。释放锁。JDK 1.8而在 JDK 1.8 中ConcurrentHashMap 主要做了两个优化同 HashMap 一样链表也会在长度达到 8 的时候转化为红黑树这样可以提升大量冲突时候的查询效率以某个位置的头结点链表的头结点或红黑树的 root 结点为锁配合自旋 CAS 避免不必要的锁开销进一步提升并发性能。相比 JDK1.7 中的 ConcurrentHashMapJDK1.8 中的 ConcurrentHashMap 取消了 Segment 分段锁采用 CAS synchronized 来保证并发安全性整个容器只分为一个 Segment即 table 数组。JDK1.8 中的 ConcurrentHashMap 对节点 Node 类中的共享变量和 JDK1.7 一样使用 volatile 关键字保证多线程操作时变量的可见性static class NodeK,V implements Map.EntryK,V { final int hash; final K key; volatile V val; volatile NodeK,V next; Node(int hash, K key, V val, NodeK,V next) { this.hash hash; this.key key; this.val val; this.next next; } ...... }ConcurrentHashMap 的字段1、tablevolatile Node[] table:装载 Node 的数组作为 ConcurrentHashMap 的底层容器采用懒加载的方式直到第一次插入数据的时候才会进行初始化操作数组的大小总是为 2 的幂次方。2、nextTablevolatile Node[] nextTable扩容时使用平时为 null只有在扩容的时候才为非 null3、sizeCtlvolatile int sizeCtl该属性用来控制 table 数组的大小根据是否初始化和是否正在扩容有几种情况当值为负数时如果为-1 表示正在初始化如果为 -N 则表示当前正有 N-1 个线程进行扩容操作当值为正数时如果当前数组为 null 的话表示 table 在初始化过程中sizeCtl 表示为需要新建数组的长度若已经初始化了表示当前数据容器table 数组可用容量也可以理解成临界值插入节点数超过了该临界值就需要扩容具体指为数组的长度 n 乘以 加载因子 loadFactor当值为 0 时即数组长度为默认初始值。4、sun.misc.Unsafe U在 ConcurrentHashMap 的实现中可以看到用了大量的U.compareAndSwapXXXX方法去修改 ConcurrentHashMap 的一些属性。这些方法实际上是利用了 CAS 算法用于保证线程安全性这是一种乐观策略假设每一次操作都不会产生冲突当且仅当冲突发生的时候再去尝试。我们前面也讲过了CAS 操作依赖于现代处理器指令集通过底层的CMPXCHG指令实现。CAS(V,O,N)核心思想为若当前变量实际值 V 与期望的旧值 O 相同则表明该变量没被其他线程进行修改因此可以安全的将新值 N 赋值给变量若当前变量实际值 V 与期望的旧值 O 不相同则表明该变量已经被其他线程做了处理此时将新值 N 赋给变量操作就是不安全的在进行重试。在并发容器中CAS 是通过sun.misc.Unsafe类实现的该类提供了一些可以直接操控内存和线程的底层操作可以理解为 Java 中的“指针”。该成员变量的获取是在静态代码块中static { try { U sun.misc.Unsafe.getUnsafe(); ....... } catch (Exception e) { throw new Error(e); } }以上是第一部分的主要内容。

相关新闻

AI写论文不容错过!4款AI论文写作工具,让你的论文脱颖而出!

AI写论文不容错过!4款AI论文写作工具,让你的论文脱颖而出!

AI论文助手工具介绍 在2025年的学术写作智能化浪潮中,越来越多的人选择AI写论文工具来帮助自己,而针对硕士和博士论文等较长篇幅的学术作品,很多AI论文写作工具却无法满足需求。这些工具常常缺乏应有的理论深度,让研究者在内容上…

2026/7/6 12:24:22 阅读更多 →
程序员必看:如何像带新员工一样“训练“你的AI智能体

程序员必看:如何像带新员工一样“训练“你的AI智能体

文章通过"新员工"的生动比喻解释了大模型智能体(Agent)的工作原理。智能体如同职场新人,需要通过"系统提示词"了解角色职责,配备"工具"完成工作。其流程是:理解任务→尝试解决→根据反馈优化。开发者需优化提示…

2026/7/6 8:56:05 阅读更多 →
Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟

Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟

Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟 🐢 🔗 上下文切换:CPU 的“换挡”开销 在上一章中,我们探讨了调度器如何通过进程迁移来实现 CPU 负载均衡。我们提到了迁移是有成本的,这个成本的核心就是 上…

2026/7/3 17:52:42 阅读更多 →

最新新闻

3分钟快速上手!DeepL翻译插件让浏览器变身智能翻译助手

3分钟快速上手!DeepL翻译插件让浏览器变身智能翻译助手

3分钟快速上手!DeepL翻译插件让浏览器变身智能翻译助手 【免费下载链接】deepl-chrome-extension A DeepL Translator Chrome extension 项目地址: https://gitcode.com/gh_mirrors/de/deepl-chrome-extension 还在为阅读外文网页而苦恼吗?DeepL …

2026/7/6 12:23:05 阅读更多 →
Linux Mint桌面深度仿Mac:从WhiteSur主题到Dock栏的完整美化指南

Linux Mint桌面深度仿Mac:从WhiteSur主题到Dock栏的完整美化指南

1. 为什么选择Linux Mint仿Mac美化?每次看到同事的MacBook Pro那精致的界面,你是不是也心动过?但动辄上万的售价又让人望而却步。其实,用Linux Mint配合WhiteSur主题套件,完全可以打造出90%相似度的Mac风格桌面&#x…

2026/7/6 12:23:05 阅读更多 →
告别终端混乱:Royal TSX在Mac上构建高效SSH连接管理体系的实战指南

告别终端混乱:Royal TSX在Mac上构建高效SSH连接管理体系的实战指南

1. 为什么Mac用户需要Royal TSX管理SSH连接作为长期管理多台Linux服务器的运维人员,我深刻理解那种打开终端后面对几十个未命名标签页的崩溃感。Mac自带的终端和iTerm2虽然能完成基础连接,但当需要同时管理开发环境、测试集群和生产服务器时,…

2026/7/6 12:23:05 阅读更多 →
Ubuntu服务器无头模式下的GPU风扇智能调速方案

Ubuntu服务器无头模式下的GPU风扇智能调速方案

1. 无头服务器GPU风扇控制的必要性当你把Ubuntu服务器塞进机柜深处时,最头疼的莫过于显卡风扇的"直升机起降"声。我去年部署的AI训练集群就遇到过这种情况——半夜里风扇突然满速旋转,活像台喷气发动机。这种噪音污染不仅影响办公环境&#xf…

2026/7/6 12:21:04 阅读更多 →
Linux Swap分区动态调整与性能调优实战指南

Linux Swap分区动态调整与性能调优实战指南

1. 为什么需要动态调整Swap分区?第一次在线上服务器遇到OOM(内存溢出)导致服务崩溃时,我才真正理解Swap的重要性。那是个运行MySQL的4GB内存云服务器,凌晨三点突然宕机,第二天查看日志才发现是物理内存耗尽…

2026/7/6 12:17:00 阅读更多 →
RHEL 5/6 与 CentOS 7/8 镜像:4种方案构建本地YUM源实战

RHEL 5/6 与 CentOS 7/8 镜像:4种方案构建本地YUM源实战

企业级Linux环境下的本地YUM源构建全攻略在无法访问外网或网络受限的企业环境中,运维工程师经常面临软件包依赖管理和系统更新的挑战。本文将深入探讨四种基于RHEL/CentOS ISO镜像构建本地YUM源的实用方案,帮助您建立稳定高效的离线软件仓库。1. 准备工作…

2026/7/6 12:10:50 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻