Map系列之ConcurrentHashMap源码分析:高并发场景下的性能密码

引言:当线程安全成为刚需

1.1 并发时代的Map困境

  • 经典案例:电商秒杀系统超卖事故分析(附线程堆栈截图)
  • 传统方案缺陷:synchronizedMap的吞吐量陷阱(JMH测试数据对比)
  • ConcurrentHashMap的定位:高并发场景下的"瑞士军刀"

1.2 版本演进时间线

JDK版本核心改进性能提升幅度
1.5分段锁架构5.8倍
1.8CAS+synchronized混合锁3.2倍
1.9+Node数组动态扩容19%

一、架构解密:ConcurrentHashMap核心设计

1.1 数据结构演进

1.1.1 Node数组进化史
// JDK1.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;
}
  • CAS进化:从分段锁到CAS+synchronized的混合锁机制
  • 红黑树优化:链表转树阈值从8调整到6(JDK1.8.0_302)
1.1.2 动态扩容机制
// 扩容触发条件(JDK1.8)
final void tryPresize(int size) {int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1);int sc = resizeStamp(n) << RESIZE_STAMP_SHIFT;while (!U.compareAndSwapInt(this, SIZECTL, sc, -1)) {// CAS扩容控制}// ...扩容逻辑...
}
  • 双缓冲扩容:transferIndex分段迁移策略
  • 协助扩容:扩容期间其他线程可参与数据迁移

二、并发控制:锁的精密舞蹈

2.1 锁分段技术演进

2.1.1 分段锁(JDK1.5)
// Segment结构(已废弃)
static final class Segment<K,V> extends ReentrantLock {transient volatile HashEntry<K,V>[] table;
}
  • 优势:减少锁粒度
  • 缺陷:内存占用增加50%
2.1.2 混合锁(JDK1.8+)
// putVal方法核心逻辑
final V putVal(K key, V value, boolean onlyIfAbsent) {if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)// CAS插入新节点else if ((fh = p.hash) >= 0) {// synchronized锁定当前桶}// ...红黑树处理逻辑...
}
  • 锁升级机制:从CAS到synchronized的渐进式加锁
  • 无锁读取:volatile变量保证可见性

2.2 并发操作全解析

2.2.1 size()方法实现
// 映射计数原理
public int size() {long n = sumCount();return ((n < 0L) ? 0 : (n >= Long.MAX_VALUE) ? Long.MAX_VALUE : n);
}// sumCount方法
final long sumCount() {CounterCell[] as = counterCells; // 分离计数数组CounterCell a;long sum = baseCount;if (as != null) {for (int i = 0; i < as.length; ++i) {if ((a = as[i]) != null)sum += a.value;}}return sum;
}
  • 分段统计:CounterCell数组分散计数压力
  • 伪原子性:弱一致性保证

三、实战应用:性能调优实战

3.1 典型场景优化

3.1.1 秒杀系统库存管理
// 正确使用姿势
ConcurrentHashMap<String, AtomicInteger> stockMap = new ConcurrentHashMap<>();void seckill(String itemId, int count) {stockMap.computeIfPresent(itemId, (k, v) -> {int remain = v.addAndGet(-count);if (remain < 0) {v.addAndGet(count); // 库存回滚return v;}return v;});
}
  • 原子操作:computeIfPresent保证原子性
  • 防超卖:回滚机制保障数据一致性
3.1.2 配置中心热加载
// 配置热更新示例
ConcurrentHashMap<String, String> configMap = new ConcurrentHashMap<>();void loadConfig() {Map<String, String> newConfig = fetchRemoteConfig();configMap.forEach((k, v) -> {if (!newConfig.containsKey(k)) {configMap.remove(k); // 安全删除旧配置}});newConfig.forEach(configMap::putIfAbsent);
}
  • 安全更新:forEach+putIfAbsent组合操作
  • 内存优化:弱引用+ReferenceQueue自动清理

四、性能解密:基准测试数据

4.1 多维性能对比

测试场景ConcurrentHashMapsynchronizedMap性能差异
10线程随机读18.2M ops/s3.1M ops/s5.8倍
100线程混合读写9.7M ops/s1.2M ops/s8.1倍
1000线程压力测试2.3M ops/sOOM-

4.2 JVM参数调优指南

推荐参数配置
-XX:+UseNUMA               # 启用NUMA内存分配
-XX:-UseBiasedLocking      # 禁用偏向锁(高并发场景)
-XX:ResizeTLAB=true        # 自动调整TLAB大小
  • 内存优化:设置-XX:ConcGCThreads=4提升GC效率
  • 锁优化:-XX:-ReduceInitialCardMarks减少标记开销

五、避坑指南:常见陷阱与对策

5.1 典型错误案例

5.1.1 并发扩容死锁
// 错误示例:扩容期间迭代操作
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
new Thread(() -> map.keySet().forEach(System.out::println)).start();
// ...其他线程执行putAll触发扩容...
  • 现象:抛出ConcurrentModificationException
  • 解决方案:使用ConcurrentHashMap.KeySetView的immutableSnapshot()
5.1.2 computeIfAbsent陷阱
// 死循环风险
map.computeIfAbsent("key", k -> {map.put("key", "value"); // 可能导致递归调用return "value";
});
  • 原理:compute系列方法会锁住当前桶
  • 对策:避免在计算函数中修改同一个键值

结语:并发编程的未来展望

6.1 技术演进方向

  • 协程支持:Project Loom对并发集合的影响
  • 硬件级优化:利用C++20原子操作提升性能
  • 云原生适配:Kubernetes环境下的自动扩缩容策略

6.2 学习路线推荐

  1. 源码精读:重点研究JDK1.8的ForwardingNode实现
  2. 性能调优:使用JFR分析扩容期间的GC行为
  3. 模式扩展:实现带TTL的ConcurrentHashMap

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/79123.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

URP - 序列图动画的实现

效果&#xff1a; 【太妃糖耶】更新了一条视频&#xff0c;快来围观&#xff01; 序列图动画的实现 首先先了解下序列图样式的纹理图片 如上图一可在Shader中使用该图片制作燃烧的火的动画&#xff0c;但是如何实现呢&#xff1f;接下来一起来看一下吧 序列图动画的实现原理大…

python中 str.strip() 是什么意思

在 Python 中&#xff0c;str.strip() 是字符串&#xff08;str&#xff09;类型的一个方法&#xff0c;用于移除字符串两端的空白字符&#xff08;默认情况下&#xff09;或指定字符&#xff0c;并返回处理后的新字符串。 语法&#xff1a; str.strip([chars])chars&#xf…

记录idea可以运行但是maven install打包却找不到问题

解决idea使⽤maven多模块install报依赖模块的包找不到的问题 如果被依赖项⽬是springboot项⽬&#xff0c;那么可以把相关的springboot的东西移除掉&#xff0c;改造成普通项⽬。如果不想改造项⽬&#xff0c;那就添加部分的配置&#xff0c;因为springboot项⽬打包的时候会⽣…

uniapp如何获取安卓原生的Intent对象

通过第三方app唤起&#xff0c;并且获取第三方app唤起时携带的参数 因为应用a唤起应用b时&#xff0c;应用b第一时间就要拿到参数token&#xff0c;所以需要将获取参数的方法写在APP.vue中的onLaunch钩子里,如果其他地方要用可以选择vuex或者采用本地缓存。 uniapp中plus.run…

《多端统一的终极答案:X5内核增强版的渲染优化全解析》

跨端应用的需求呈爆发式增长&#xff0c;无论是电商购物、社交互动&#xff0c;还是金融理财类应用&#xff0c;都期望能够在不同平台上为用户提供一致且流畅的体验。而在这一过程中&#xff0c;跨端渲染技术成为了关键瓶颈。腾讯X5内核增强版的出现&#xff0c;犹如一道曙光&a…

深入理解算力:从普通电脑到宏观计算世界

在科技飞速发展的当下&#xff0c;“算力” 一词频繁出现在我们的视野中&#xff0c;无论是前沿的人工智能领域&#xff0c;还是新兴的区块链世界&#xff0c;算力都扮演着至关重要的角色。但对于大多数普通人来说&#xff0c;算力仿佛是一个既熟悉又陌生的概念。今天&#xff…

Paramiko复用 Transport 连接解析

1. 什么是 Transport 连接&#xff1f; 在 Paramiko 中&#xff0c;Transport 是负责底层 SSH 协议通信的核心类&#xff0c;它封装了以下功能&#xff1a; 加密通信&#xff1a;处理 SSH 协议的加密和解密。会话管理&#xff1a;维护与远程服务器的 TCP 连接。多路复用&…

sd webui 安装插件sd-webui-EasyPhoto依赖安装失败解决办法

在最新版的SD webui中&#xff0c;可以安装easyphoto插件&#xff0c;官方建议通过github安装&#xff0c;对无法科学上网的用户很不友好。对我自己来说是通过地址&#xff1a; https://gitee.com/wowai/sd-webui-EasyPhoto.git 分支&#xff1a;anyid 点击安装即可。 在安装…

WEBSTORM前端 —— 第2章:CSS —— 第3节:背景属性与显示模式

目录 1.Emmet写法 2.背景属性 &#xff08;1&#xff09; background-color &#xff08;2&#xff09; background-image &#xff08;3&#xff09; background-repeat &#xff08;4&#xff09;background-position &#xff08;5&#xff09;background-size &…

【android bluetooth 协议分析 01】【HCI 层介绍 2】【Malformed Packet 介绍】

在实际工作中遇到了 malformed packet , 我这里来分析一下。 遇到这种问题的处理思路。 1. Malformed packet 36982 2025-04-29 14:15:34.899760 controller host HCI_EVT 4 Rcvd Role Change[Malformed Packet]Frame 36982: 4 bytes on wire (32 bits), 4 bytes captured (32…

【视频生成模型】通义万相Wan2.1模型本地部署和LoRA微调

目录 1 简介2 本地部署2.1 配置环境2.2 下载模型 3 文生视频3.1 运行命令3.2 生成结果 4 图生视频4.1 运行命令4.2 生成结果 5 首尾帧生成视频5.1 运行命令5.2 生成结果 6 提示词扩展7 LoRA微调 1 简介 通义万相 2.1 在 2025 年 1 月推出&#xff0c;2 月 25 日阿里巴巴宣布全…

模式识别的基本概念与理论体系

前面在讨论专家系统时曾经说过&#xff0c;为了使计算机具有自动获取知识的能力&#xff0c;除了应使它具有学习能力外&#xff0c;还应使它具有能识别诸如文字、图形、图象、声音等的能力&#xff0c;计算机的这种识别能力是模式识别研究的主要内容。当然&#xff0c;模式识别…

树的序列化 - 学习笔记

树的序列化可以有很多种类&#xff1a;可以变成 dfs 序&#xff0c;可以变成欧拉序&#xff0c;还有什么括号序的科技。 但是除了第一个以外其他的都没什么用&#xff08;要么也可以被已有的算法给替代掉&#xff09;。所以表面上是讲树的序列化&#xff0c;实际上还是讲的 df…

KBEngine 源代码分析(三):组网逻辑

machine 服务 machine 服务是 KBEngine 用来做服务治理的 每个节点上都需要部署 machine 服务 machine 服务使用 UDP 进行通信 服务发现的方法是其他服务使用 UDP 广播的方式,通知所有 machine 服务 machine 服务启动初始化 mahcine 服务初始化过程,主要做了监听 UDP 端…

git 怎样把本地仓库推送到新建的远程仓库

将本地 Git 仓库推送到一个新的远程仓库是一个常见的操作。以下是详细的步骤&#xff1a; 步骤 1: 创建一个新的远程仓库 首先&#xff0c;你需要在 GitHub、GitLab 或其他代码托管平台上创建一个新的远程仓库。 例如&#xff0c;在 GitHub 上创建一个新仓库&#xff1a; 登…

SPSS PCA+判别分析

1&#xff0c; 主成分分析PCA 我们只要对数化的变量数据&#xff1a; &#xff08;1&#xff09;对数据进行标准化处理&#xff1a; 选择【分析】—【描述统计】—【描述】 添加要标准化的变量&#xff0c;勾选【将标准化值另存为变量(Z)】&#xff0c;再点确定 SPSS软件本身不…

XWPFDocument生成word文档介绍(格式 .docx)

以下是针对 XWPFDocument 的详细解析&#xff0c;涵盖其核心功能、常见用法及实际开发中的关键点&#xff1a; XWPFDocument 1. XWPFDocument 简介2. 核心结构与类3. 核心操作详解**3.1 段落与文本****3.2 表格操作****3.3 列表与编号****3.4 图片插入** 4. 高级功能**4.1 页眉…

crashpad 编译

一环境配置 1.1设置系统UTF8编码 1.2vs2017语言环境设置英文包 二.获取depot_tools&#xff08;此步骤可以跳过 最新工具包已上传下载使用即可&#xff09; windows下载压缩包&#xff0c;然后放到系统PATH中 下载完以后&#xff0c;基本就是靠depot_tools这个工具集合了&am…

基于标注数据的情感分析模型研究

标题:基于标注数据的情感分析模型研究 内容:1.摘要 随着互联网的快速发展&#xff0c;大量文本数据蕴含着丰富的情感信息&#xff0c;对其进行情感分析具有重要的商业和社会价值。本研究的目的是构建基于标注数据的情感分析模型&#xff0c;以准确识别文本中的情感倾向。方法上…

【数据链路层深度解析】从帧结构到协议实现

目录 一、数据链路层核心定位1.1 OSI模型中的位置1.2 三大核心职责 二、帧结构详解2.1 以太网帧标准格式&#xff08;IEEE 802.3&#xff09;2.2 帧封装代码示例 三、核心协议机制3.1 MAC地址体系3.2 介质访问控制CSMA/CD&#xff08;以太网冲突检测&#xff09;现代交换机的演…