深入解析 ConcurrentHashMap:从 JDK 1.7 到 JDK 1.8
✨探索Java基础 ConcurrentHashMap✨
引言
ConcurrentHashMap
是 Java 中一个线程安全的高效 Map 集合。它在多线程环境下提供了高性能的数据访问和修改能力。本文将详细探讨 ConcurrentHashMap
在 JDK 1.7 和 JDK 1.8 中的不同实现方式,以及它们各自的优缺点。
基本概念
ConcurrentHashMap
是一个线程安全的哈希表实现,适用于高并发场景。它的设计目标是在保证线程安全的同时,提供尽可能高的性能。
JDK 1.7 版本的 ConcurrentHashMap
接下来看一张图片:
数据结构
在 JDK 1.7 中,ConcurrentHashMap
使用 分段锁(Segment) 的设计。每个 Segment 是一个独立的小哈希表,并且每个 Segment 都有自己的锁。这种设计允许多个线程同时访问不同的 Segment,从而提高并发性能。
- Segment 数组:默认是 16 个 Segment。
- HashEntry 数组:每个 Segment 内部有一个 HashEntry 数组,用于存储具体的元素。
- 链表:如果发生哈希冲突,会使用单向链表来存储冲突的节点。
存储流程
- 计算 key 的哈希值:通过 key 的哈希值确定 Segment 数组的下标。
- 获取 Segment 锁:对对应的 Segment 进行加锁。
- 确定 HashEntry 数组下标:再次通过哈希值确定 HashEntry 数组中的下标。
- 存储数据:将数据存入 HashEntry 数组中,如果发生冲突,则挂载到单向链表上。
- 附图:
扩容机制
- 基于 Segment:每个 Segment 维护自己的负载因子,当某个 Segment 中的元素数量超过阈值时,该 Segment 会单独进行扩容。
- 局部扩容:只影响当前 Segment,不会影响其他 Segment。
size 方法
- 尝试三次不加锁获取 sum:如果三次总数相同,直接返回;否则,加锁计算总和。
JDK 1.8 版本的 ConcurrentHashMap
看图:
数据结构
在 JDK 1.8 中,ConcurrentHashMap
取消了 Segment 设计,采用了与 HashMap
类似的数据结构:数组 + 链表/红黑树。
- Node 数组:类似于
HashMap
的数组。 - 链表/红黑树:当链表长度超过一定阈值时,会转换为红黑树以提高查询效率。
存储流程
- 计算 key 的哈希值:通过 key 的哈希值确定 Node 数组的下标。
- CAS 添加新节点:使用 CAS 操作尝试添加新节点。
- 锁定首节点:如果 CAS 失败或需要更新链表/红黑树,使用
synchronized
锁定首节点。 - 存储数据:将数据存入链表或红黑树中。
扩容机制
- 全局扩容:当整个
ConcurrentHashMap
的元素数量超过阈值时,整个数组会进行扩容。 - 渐进式扩容:多个线程共同参与扩容操作,逐步迁移旧数据到新数组中,降低扩容时的性能开销。
size 方法
- 类似 LongAdder 的思想:使用
baseCount
和counterCells
数组来维护计数。 - 减少竞争:通过分散计数到多个
counterCell
来减少对单个变量的竞争压力。
代码示例
JDK 1.7 版本
// Segment 类
static final class Segment<K,V> extends ReentrantLock implements Serializable {private final int threshold;transient volatile HashEntry<K,V>[] table;transient int count;transient int modCount;// 构造函数Segment(int initialCapacity, float loadFactor) {this.threshold = (int) (initialCapacity * loadFactor);setTable(HashEntry.<K,V>newArray(initialCapacity));}// put 方法V put(K key, int hash, V value, boolean onlyIfAbsent) {lock(); // 加锁try {int c = count;if (c++ > threshold) // 需要扩容rehash();HashEntry<K,V>[] tab = table;int index = hash & (tab.length - 1);HashEntry<K,V> first = tab[index];HashEntry<K,V> e = first;while (e != null && (e.hash != hash || !key.equals(e.key)))e = e.next;V oldValue;if (e != null) {oldValue = e.value;if (!onlyIfAbsent)e.value = value;} else {oldValue = null;++modCount;tab[index] = new HashEntry<>(key, hash, first, value);}return oldValue;} finally {unlock(); // 解锁}}
}
JDK 1.8 版本
// Node 类
static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;volatile V val;volatile Node<K,V> next;Node(int hash, K key, V val, Node<K,V> next) {this.hash = hash;this.key = key;this.val = val;this.next = next;}public final K getKey() { return key; }public final V getValue() { return val; }public final String toString() { return key + "=" + val; }
}// putVal 方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // 转换为红黑树treeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // 存在键冲突V oldValue = e.val;if (!onlyIfAbsent || oldValue == null)e.val = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;
}
总结
- JDK 1.7:使用分段锁(Segment)和
ReentrantLock
,每个 Segment 是一个独立的小哈希表,适合中等并发场景。 - JDK 1.8:采用 CAS 操作和
synchronized
锁定链表或红黑树的首节点,提供了更细粒度的锁,适合高并发场景。
通过这些改进,JDK 1.8 版本的 ConcurrentHashMap
在性能和并发控制方面有了显著的提升。
觉得有用的话可以点点赞 (*/ω\*),支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。
相关文章:

深入解析 ConcurrentHashMap:从 JDK 1.7 到 JDK 1.8
✨探索Java基础 ConcurrentHashMap✨ 引言 ConcurrentHashMap 是 Java 中一个线程安全的高效 Map 集合。它在多线程环境下提供了高性能的数据访问和修改能力。本文将详细探讨 ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 中的不同实现方式,以及它们各自的优缺点。 …...

VS code user setting 与 workspace setting 的区别
VS code user setting 与 workspace setting 的区别 引言正文引言 相信有不少开始接触 VS code 的小伙伴会有疑问,user setting 与 workspace setting 有什么区别呢?这里我们来说明一下 正文 首先,当我们使用 Ctrl + Shift + P 打开搜索输入 setting 后,可以弹出 4 个se…...
XPath基础知识点讲解——用于在XML中查找信息的语言
1. 什么是XPath? XPath(XML Path Language)是用于在XML(Extensible Markup Language)文档中查找信息的语言。它可以通过路径表达式来选择XML文档中的节点,类似于如何在文件系统中使用路径查找文件。XPath是…...
Visual Studio 2022
VS(Visual Studio)是一款由微软开发的集成开发环境(IDE),用于开发应用程序、网站以及移动应用等。VS的历史可以追溯到1997年,当时发布了第一个版本的VS。以下是VS的一些重要历史里程碑: Visual …...

微软Win11 22H2/23H2 九月可选更新KB5043145发布!
系统之家于9月27日发出最新报道,微软针对Windows11系统,发布了九月最新可选更新补丁KB5043145,22H2用户安装后,系统版本号升至22621.4249,23H2用户安装后升至22631.4249。本次更新修复了Edge使用IE模式有时会停止响应等…...

试试号称最好的7B模型(论文复现)
试试号称最好的7B模型(论文复现) 本文所涉及所有资源均在传知代码平台可获取 文章目录 试试号称最好的7B模型(论文复现)概述论文原理部署与复现推理微调adapter 融合 概述 Mistral 7B 是一个新型的具有 7.3 万亿参数的大语言模型。…...
CTF中文件包含
php伪协议的分类 伪协议是文件包含的基础,理解伪协议的原理才能更好的利用文件包含漏洞。 php://input php://input代表可以访问请求的原始数据,简单来说POST请求的情况下,php://input可以获取到post的数据。 使用条件:includ…...

20.指针相关知识点1
指针相关知识点1 1.定义一个指针变量指向数组2.指针偏移遍历数组3.指针偏移的补充4.指针和数组名的见怪不怪5.函数、指针、数组的结合 1.定义一个指针变量指向数组 指向数组首元素的地址 指向数组起始位置:等于数组名 #include <stdio.h>int main(){int ar…...

PFC和LLC的本质和为什么要用PFC和LLC电路原因
我们可以用电感和电容的特性,以及电压和电流之间的不同步原理来解释PFC(功率因数校正)和LLC(谐振变换器)。 电感和电容的基本概念 电感(Inductor): 电感是一种储存电能的组件。它的电流变化比较慢,电流在电感中延迟,而电压变化得比较快。可以把电感想象成一个“滞后…...

自定义认证过滤器和自定义授权过滤器
目录 通过数据库动态加载用户信息 具体实现步骤 一.创建数据库 二.编写secutity配置类 三.编写controller 四.编写服务类实现UserDetailsService接口类 五.debug springboot启动类 认证过滤器 SpringSecurity内置认证流程 自定义认证流程 第一步:自定义一个类继承Abstr…...
单节点集群的设置及数据写入
背景:elasticsearch单个node节点写入数据-CSDN博客 单个节点数据,如下设置参数, 在单节点集群中,设置 `gateway.recover_after_nodes` 通常是没有意义的,因为单节点集群只有一个节点,无法满足 `gateway.recover_after_nodes` 的条件。然而,如果你仍然想在单节点集群中…...

【Linux学习】【Ubuntu入门】1-2 新建虚拟机ubuntu环境
1.双击打开VMware软件,点击“创建新的虚拟机”,在弹出的中选择“自定义(高级)” 2.点击下一步,自动识别ubuntu光盘映像文件,也可以点击“浏览”手动选择,点击下一步 3.设置名称及密码后…...

自动驾驶系列—自动驾驶MCU架构全方位解析:从单核到多核的选型指南与应用实例
🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…...

基于单片机多功能称重系统设计
** 文章目录 前言概要功能设计设计思路 软件设计效果图 程序文章目录 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对…...

PWA(Progressive web APPs,渐进式 Web 应用): manifest.json、 Service Worker
文章目录 引言I 什么是 PWA功能特性技术上分为三个部分安装应用II Web 应用清单将Web 应用清单文件链接到站点manifest.json字段说明III Service Worker( 缓存管理)IV 结合构建工具让项目支持 PWA应用使用插件vite-plugin-pwaworkbox-webpack-plugin插件扩展知识将 PWA 作为脱机…...

【学习笔记】手写 Tomcat 八
目录 一、NIO 1. 创建 Tomcat NIO 类 2. 启动 Tomcat 3. 测试 二、解析请求信息 三、响应数据 创建响应类 修改调用的响应类 四、完整代码 五、测试 六、总结 七、获取全部用户的功能 POJO 生成 POJO 1. 在 Dao 层定义接口 2. 获取用户数据 3. 在 Service 层定…...

24年九月份生活随笔
九月份最后一天,烈士纪念日。 上午看了一会儿直播,庄重的仪式,铭记先辈为新中国抛头颅洒热血,当今盛世,如您所愿。 郑州马拉松官方通告,今天十点公布直通,中签,候补结果。 看完直…...

[含文档+PPT+源码等]精品大数据项目-基于Django实现的高校图书馆智能推送系统的设计与实现
大数据项目——基于Django实现的高校图书馆智能推送系统的设计与实现背景,可以从以下几个方面进行详细阐述: 一、信息技术的发展背景 随着信息技术的飞速发展和互联网的广泛普及,大数据已经成为现代社会的重要资源。在大数据背景下…...

Leecode刷题之路第七天之整数反转
题目出处 07-整数反转 题目描述 个人解法 思路: 1.将整数转换为字符串 2.倒序输出字符串 3.兼容负数case 代码示例:(Java) public int reverse(int x) {Integer integer new Integer(x);String s integer.toString();Strin…...

SpringBoot项目 | 瑞吉外卖 | 短信发送验证码功能改为免费的邮箱发送验证码功能 | 代码实现
0.前情提要 之前的po已经说了单独的邮箱验证码发送功能怎么实现: https://blog.csdn.net/qq_61551948/article/details/142641495 这篇说下如何把该功能整合到瑞吉项目里面,也就是把原先项目里的短信发送验证码的功能改掉,改为邮箱发送验证…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...