文章目录

  • 一、HashMap在JDK1.7中的并发问题
  • 二、死链如何产生?
  • 三、如何解决HashMap并发问题
  • 参考文献

一、HashMap在JDK1.7中的并发问题

在JDK1.7中的HashMap是以数组+链表组成的,我们先来看一下每次的put操作,可以分为以下三步:

  • 寻址

    • 1.根据key的hashcode()方法计算原始哈希值
    • 2.哈希值进一步和自身高16位做异或操作,得到更随机的hashcode
    • 3.hashcode再和数组长度-1做与操作,得到数组的下标
  • 判断是否扩容
    • 如果map中的数组元素个数超过了 数组长度 * 负载因子(0.75),则需要扩容
  • 比较并存放
    • 通过equals比较每个链表节点的值并赋值

寻址和存放都不会出现并发问题,问题就出现在扩容部分,接下来我们详细展开看一下扩容部分的源码:

  • resize方法源码:
 void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}// 创建2倍大小的新数组Entry[] newTable = new Entry[newCapacity];// 将旧数组的链表转移到新数组,就是这个方法导致的hashMap不安全,等下我们进去看一眼transfer(newTable, initHashSeedAsNeeded(newCapacity));table = newTable;// 重新计算扩容阈值(容量*加载因子)threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}

出问题的就是这个transfer方法,其作用是把旧节点转移到扩容后的新map中,从1.7源码中可以看出它使用的是头插法来插入新节点,问题也正是出现在了这里

  1. transfer方法源码:
void transfer(Entry[] newTable, boolean rehash) {int newCapacity = newTable.length;// 遍历旧数组for (Entry<K,V> e : table) {// 遍历链表while(null != e) {//获取下一个元素,记录到一个临时变量,以便后面使用Entry<K,V> next = e.next;if (rehash) {e.hash = null == e.key ? 0 : hash(e.key);}// 计算节点在新数组中的下标int i = indexFor(e.hash, newCapacity);// 将旧节点插入到新节点的头部e.next = newTable[i];//这行才是真正把数据插入新数组中,前面那行代码只是设置当前节点的next//这两行代码决定了倒序插入//比如:以前同一个位置上是:3,7,后面可能变成了:7、3newTable[i] = e;//将下一个元素赋值给当前元素,以便遍历下一个元素e = next;  }  }
}

二、死链如何产生?

假设初始状态的HashMap数据如下图

假设此时再调用下一个put方法时,发生了扩容,会new一个容量翻倍的Hashmap,如果此时有两个线程,则会同时进入扩容方法

此时t2线程率先完成transfer方法,由于是头插法,所以元素会呈现倒序状态

此时线程t1开始进入transfer方法,每次用头插法赋值前,会先记录下旧map中该节点的next节点,以便进入下一次循环

  1. t1线程挂key:3的节点
  2. t1线程挂key:7的节点,注意:在此间线程t2完成了所有新节点的赋值,所以此时7.next已经变成了3了
  3. 由于节点不为null,会再次进入循环,此时再次挂key:3,next节点又为7,从而产生了死链

    通过时序图可以更清楚的了解整个并发问题的产生

三、如何解决HashMap并发问题

为了解决这个问题,JDK1.8把扩容的复制到新数组的算法从头插法改成了尾插法,并引入了红黑树。HashMap是非线程安全的,在多线程环境下还是推荐使用ConcurrentHashMap

参考文献

https://segmentfault.com/a/1190000024510131

【死链】JDK1.7中HashMap在多线程环境的并发问题源码分析相关推荐

  1. HashMap之TreeNode(红黑树)源码分析

    HashMap-TreeNode源码分析(jdk1.8 HashMap之TreeNode源码分析 属性及构造方法 find() putTreeVal() removeTreeNode() treeif ...

  2. Java代码怎么取消订阅功能,RxJava2 中多种取消订阅 dispose 的方法梳理( 源码分析 )...

    Github 相关代码: Github地址 一直感觉 RxJava2 的取消订阅有点混乱, 这样也能取消, 那样也能取消, 没能系统起来的感觉就像掉进了盘丝洞, 迷乱... 下面说说这几种情况 几种取 ...

  3. Vue中的methods配置项中的箭头函数this指向及相关源码分析

    之前在使用Vue时遇到一个问题,我们知道在Vue的methods中定义函数时,要想使用到Vue实例或者组件实例的this时,我们就不能使用箭头函数定义方法,因为箭头函数中的this是在函数定义时生成的 ...

  4. Android SQLite多线程读写和线程同步源码分析

    没啥诀窍,只需保证几个线程都是用的一个SQLiteDataBase对象就行了. 如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作 ...

  5. VTK Examples中MIP和MPR的功能实现与源码分析

    本篇博客由Markdown编辑器编辑而成. 1. 前言 在之前关于ParaView技术调研中,已经通过修改ParaView5.0的源代码实现了MIP/minIP/aveIP的功能.但是由于对ParaV ...

  6. java中的 dispose_RxJava2 中多种取消订阅 dispose 的方法梳理( 源码分析 )

    Github 相关代码: Github地址 一直感觉 RxJava2 的取消订阅有点混乱, 这样也能取消, 那样也能取消, 没能系统起来的感觉就像掉进了盘丝洞, 迷乱- 下面说说这几种情况 几种取消的 ...

  7. linux中的文件权限drm解释,DRM内核源码分析之三

    DRM-Core 层为各家显卡driver的编写提供了通用层. 这个好像是必然的,为了复用和代码的规范:-0 Linux内核的guys为我们提高了很多接口,直接用就行了. 对DRM,注册的最关键函数是 ...

  8. Java中字符串拼接的几种方式(源码分析)

    字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起. 我们都知道,String是Java中一个不可变的类,所以他一旦被实例化就无法被修改. 不可变类的实例一旦创建,其成员变 ...

  9. java中HashMap在多线程环境下引起CPU100%的问题解决

    最近项目中出现了Tomcat占用CPU100%的情况,原以为是代码中出现死循环,后台使用jstack做了dump,发现是系统中不合理使用HashMap导致出现了死循环(注意不是死锁). 产生这个死循环 ...

最新文章

  1. .NET笔试题集(五)
  2. 当我们按下电源键,Android 究竟做了些什么?
  3. unity android模糊ios清晰,Unity NGUI UI 在iOS端的锯齿、模糊、颗粒感问题
  4. python爬虫吧-Python爬虫——抓取贴吧帖子
  5. WinCE驱动编写小结
  6. laravel 中添加自定义辅助函数helpers.php
  7. 后台编写HttpWebRequest的POST请求,必须注意的一个小细节
  8. linux下tomcat部署
  9. 混淆矩阵-python
  10. Linux网络子系统中收包软中断
  11. TCP/IP-ARP
  12. 使用Struts2和jQuery EasyUI实现简单CRUD系统(五)——jsp,json,EasyUI的结合
  13. Atitit 文档资料整理的规范流程与问题解决目录1. 减肥 11.1. 剥离非原创类文件 11.2. 去重 11.3. 转换格式 21.4. Topic主题剥离 22. 脱敏 2
  14. Kafka从上手到实践 - 初步认知:Zookeeper | 凌云时刻
  15. 太阳光轨迹软件_飞时达日照分析软件-FastSUN(日照分析软件)下载 v12.0中文版--pc6下载站...
  16. linux yast命令,Linux_SUSE Linux系统上双网卡绑定方法,1、使用yast工具配置第一块网 - phpStudy...
  17. word安装到计算机的哪里,如何查找word安装目录 如何查找word的路径
  18. 故障:笔记本开机时自动打开 NumLock 键
  19. pta第六章错题函数and编程
  20. 无悔入华夏怎么一直显示服务器,无悔入华夏快速通关攻略

热门文章

  1. xsstrike安装(仅供参考)
  2. Android学习之省份城市县区选择+向上一级活动返回数据
  3. 给计算机图片文件夹加密码,文件夹怎么设置密码
  4. VR在国内越做越“廉价”,到底需要反思什么?
  5. 打开计算机管理窗口命令,Win7如何打开命令行窗口?打开命令行窗口的方法
  6. TMS320F28379D——时钟系统
  7. donate.ouyangsong.com
  8. php防刷红包,PHP防止多次请求刷红包的方法
  9. 《乐跑宝典》读书笔记
  10. matlab显示图像全黑,请教!彩色图像显示出来怎么是全黑的?