news 2026/4/27 23:11:23

Java HashMap 多线程环境下的死链问题详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java HashMap 多线程环境下的死链问题详解

HashMap在多线程环境下使用时存在死链问题。让我详细解释一下这个问题的原因以及如何规避:

问题原因分析

在JDK 7及之前版本的HashMap中,resize时采用的是头插法重新排列链表,这会导致链表顺序反转:

// JDK 7的resize代码片段voidtransfer(Entry[]newTable){Entry[]src=table;intnewCapacity=newTable.length;for(intj=0;j<src.length;j++){Entry<K,V>e=src[j];if(e!=null){src[j]=null;do{Entry<K,V>next=e.next;// 关键点:线程A在这里读取nextinti=indexFor(e.hash,newCapacity);e.next=newTable[i];// 头插法:新节点插入到链表头部newTable[i]=e;e=next;}while(e!=null);}}}

死链产生过程:

  1. 线程A和B同时进行resize
  2. 线程A执行到Entry<K,V> next = e.next;后被挂起
  3. 线程B完成resize,链表顺序被反转
  4. 线程A恢复执行,此时它的next指向的是反转前的下一个节点
  5. 形成环形链表,导致后续操作无限循环

解决方案

1. 使用线程安全的集合类

ConcurrentHashMap(推荐)
// Java 8+ 推荐ConcurrentHashMap<String,Object>concurrentMap=newConcurrentHashMap<>();// 指定初始容量和并发级别ConcurrentHashMap<String,Object>map=newConcurrentHashMap<>(16,0.75f,16);

特点:

  • JDK 8+采用CAS + synchronized,性能更好
  • 分段锁(JDK 7)或桶级锁(JDK 8+)
  • 读写操作大部分情况下不需要全局锁
Collections.synchronizedMap
Map<String,Object>synchronizedMap=Collections.synchronizedMap(newHashMap<>());

特点:对整个map加锁,性能较差

2. 显式加锁控制

// 使用ReentrantLockpublicclassSafeHashMap<K,V>{privatefinalMap<K,V>map=newHashMap<>();privatefinalReentrantLocklock=newReentrantLock();publicVput(Kkey,Vvalue){lock.lock();try{returnmap.put(key,value);}finally{lock.unlock();}}publicVget(Kkey){lock.lock();try{returnmap.get(key);}finally{lock.unlock();}}}

3. 使用其他并发数据结构

CopyOnWrite(适合读多写少)
CopyOnWriteArrayList<String>list=newCopyOnWriteArrayList<>();CopyOnWriteArraySet<String>set=newCopyOnWriteArraySet<>();
ConcurrentLinkedQueue/Deque
ConcurrentLinkedQueue<String>queue=newConcurrentLinkedQueue<>();ConcurrentLinkedDeque<String>deque=newConcurrentLinkedDeque<>();

4. 使用读写锁(ReadWriteLock)

publicclassReadWriteMap<K,V>{privatefinalMap<K,V>map=newHashMap<>();privatefinalReadWriteLocklock=newReentrantReadWriteLock();publicVput(Kkey,Vvalue){lock.writeLock().lock();try{returnmap.put(key,value);}finally{lock.writeLock().unlock();}}publicVget(Kkey){lock.readLock().lock();try{returnmap.get(key);}finally{lock.readLock().unlock();}}}

版本差异说明

JDK 8+的改进

JDK 8中的HashMap在resize时:

  1. 保持了链表元素的顺序(尾插法)
  2. 但仍然不是线程安全的,只是减少了死链的概率
  3. 仍可能出现数据丢失、size计算错误等问题
// JDK 8使用尾插法if(loTail!=null){loTail.next=null;newTab[j]=loHead;// 保持原顺序}

最佳实践建议

1. 单线程环境

  • 使用HashMap(性能最好)

2. 多线程环境

  • 读写都频繁ConcurrentHashMap
  • 写少读多CopyOnWrite系列
  • 需要强一致性Collections.synchronizedMap或显式加锁
  • 高并发计数LongAdderConcurrentHashMap的原子操作

3. 特定场景

// 统计计数ConcurrentHashMap<String,LongAdder>counter=newConcurrentHashMap<>();counter.computeIfAbsent(key,k->newLongAdder()).increment();// 缓存实现ConcurrentHashMap<String,Future<T>>cache=newConcurrentHashMap<>();

4. 代码示例:线程安全的缓存

publicclassThreadSafeCache<K,V>{privatefinalConcurrentHashMap<K,V>cache=newConcurrentHashMap<>();privatefinalConcurrentHashMap<K,Future<V>>futures=newConcurrentHashMap<>();publicVget(Kkey,Callable<V>loader)throwsException{Vvalue=cache.get(key);if(value==null){Future<V>future=futures.computeIfAbsent(key,k->CompletableFuture.supplyAsync(()->{try{returnloader.call();}catch(Exceptione){thrownewRuntimeException(e);}}));value=future.get();cache.put(key,value);futures.remove(key);}returnvalue;}}

总结

方案线程安全性能适用场景
HashMap不安全最高单线程环境
ConcurrentHashMap安全高并发读写
Collections.synchronizedMap安全简单同步需求
显式加锁安全复杂同步逻辑
CopyOnWrite安全读高写低读多写少

核心建议:

  • 在多线程环境下,永远不要使用HashMap
  • 首选ConcurrentHashMap,它在绝大多数场景下都能提供良好的性能和线程安全
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 12:29:25

从实验到部署无缝衔接:PyTorch与CUDA集成镜像详解

从实验到部署无缝衔接&#xff1a;PyTorch与CUDA集成镜像详解 在深度学习项目中&#xff0c;最令人沮丧的场景莫过于——模型代码写完了&#xff0c;却卡在环境配置上。ImportError: libcudart.so.12、”CUDA not available”、驱动版本不匹配……这些问题反复出现&#xff0c;…

作者头像 李华
网站建设 2026/4/23 13:14:15

Markdown写技术博客引流利器:展示PyTorch模型训练成果

用 Markdown 展示 PyTorch 模型训练成果&#xff1a;高效表达与影响力构建 在深度学习项目中&#xff0c;写出一个能跑通的模型只是第一步。真正让工作产生价值的&#xff0c;是如何清晰地传达你的实验过程、技术选择和最终成果。很多开发者花了几周调模型&#xff0c;结果写出…

作者头像 李华
网站建设 2026/4/25 12:53:07

鸿鹄CAD-轻松搞定工程变更CAD图纸绘制

鸿鹄CAD-轻松搞定工程变更CAD图纸绘制 工程变更是项目实施过程中&#xff0c;由承包人、发包人或设计方提出&#xff0c;对合同内容、数量、质量、施工顺序及工艺等的调整。本文为大家讲解工程变更的几个常见种类、变更单模板和相应要求。以及面对图纸变更&#xff0c;如何使用…

作者头像 李华
网站建设 2026/4/27 12:25:36

SSH multiplexing复用连接:频繁登录PyTorch服务器更高效

SSH Multiplexing复用连接&#xff1a;频繁登录PyTorch服务器更高效 在深度学习工程实践中&#xff0c;一个看似不起眼却高频发生的操作——反复通过SSH登录远程GPU服务器——往往成为拖慢开发节奏的“隐形瓶颈”。尤其是在使用PyTorch这类对环境依赖复杂的框架时&#xff0c;开…

作者头像 李华
网站建设 2026/4/27 4:04:39

跟网型新能源接入对多馈入直流换相失败风险区域的影响研究

跟网型新能源接入对多馈入直流换相失败风险区域的影响研究 本文研究跟网型光伏电站接入多馈入直流系统时对换相失败风险区域的影响。通过建立换相失败临界电压模型,分析新能源位置与容量对系统电压稳定性的作用机制。提出基于电压相互作用影响因子的快速风险评估方法,揭示新…

作者头像 李华
网站建设 2026/4/21 22:36:50

PyTorch-CUDA-v2.8镜像安全性升级:修复CVE漏洞组件

PyTorch-CUDA-v2.8镜像安全性升级&#xff1a;修复CVE漏洞组件 在深度学习项目快速迭代的今天&#xff0c;一个稳定、安全且开箱即用的开发环境&#xff0c;往往比模型结构本身更能决定团队的研发效率。尤其是在企业级AI平台中&#xff0c;研究人员和工程师不再满足于“能跑起来…

作者头像 李华