news 2026/4/23 8:58:33

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/21 0:50:01

论文写作终极救星:9款免费AI工具一键极速生成,覆盖全场景!

还在为论文选题、结构、写作和降重而彻夜难眠吗&#xff1f;告别焦虑与低效&#xff0c;这篇指南就是你的终极解决方案。我们深度测评了市面上数十款AI工具&#xff0c;为你精选出9款真正能打的免费神器&#xff0c;覆盖从文献检索到终稿润色的全流程。阅读本文&#xff0c;你将…

作者头像 李华
网站建设 2026/4/23 6:38:38

钻井井喷关井期间井筒压力变化特征

钻井井喷关井期间井筒压力变化特征 该论文针对钻井井喷关井期间井筒压力计算值与实际值差异大的问题,将关井过程分为两个阶段:初期地层流体继续侵入的续流阶段和气液密度差导致气体滑脱上升阶段。建立了考虑井筒弹性、流体压缩性的续流模型和气液两相流滑脱模型,综合得到井…

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

YOLOv5模型剪枝压缩:基于PyTorch实现FPGM算法

YOLOv5模型剪枝压缩&#xff1a;基于PyTorch实现FPGM算法 在边缘计算设备日益普及的今天&#xff0c;如何将高性能目标检测模型高效部署到资源受限的硬件上&#xff0c;已成为工业界和学术界共同关注的核心问题。以YOLOv5为代表的实时检测模型虽然精度高、推理快&#xff0c;但…

作者头像 李华
网站建设 2026/4/23 6:39:35

PyTorch分布式训练Horovod集成:跨节点扩展方案

PyTorch分布式训练Horovod集成&#xff1a;跨节点扩展方案 在深度学习模型参数动辄上百亿的今天&#xff0c;单卡训练已经远远无法满足研发效率的需求。一个典型的ResNet-50模型在ImageNet上训练一次可能需要数天时间&#xff0c;而像BERT、ViT这样的大模型更是动辄周级别的训练…

作者头像 李华
网站建设 2026/4/23 6:36:39

JiyuTrainer可视化界面:一键启动PyTorch训练任务

JiyuTrainer可视化界面&#xff1a;一键启动PyTorch训练任务 在人工智能项目开发中&#xff0c;最让人头疼的往往不是模型设计本身&#xff0c;而是环境配置——明明代码写好了&#xff0c;却因为CUDA版本不匹配、PyTorch编译失败或GPU驱动缺失&#xff0c;导致训练任务迟迟无法…

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

GitHub Discussions社区互动:解答PyTorch用户疑问

GitHub Discussions社区互动&#xff1a;解答PyTorch用户疑问 在深度学习项目开发中&#xff0c;你是否曾因环境配置问题耗费数小时&#xff1f;明明代码逻辑无误&#xff0c;却在运行时遭遇 CUDA out of memory 或 ImportError: libcudart.so not found 这类错误。对于许多刚…

作者头像 李华