概念1:Rehash的概念?
Rehash 是HashMap在扩容时候的一个步骤。

HashMap的容量是有限的。当经过多次元素插入,使得HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高。

这时候,HashMap需要扩展它的长度,也就是进行Resize

影响发生Resize的因素有两个:
1.Capacity(HashMap的当前长度–容量)
HashMap的当前长度。上一期曾经说过,HashMap的长度是2的幂。

2.LoadFactor(负载因子)
HashMap负载因子,默认值为0.75f

衡量HashMap是否进行Resize的条件如下:
HashMap.Size >= Capacity * LoadFactor (默认情况下是 == 原来长度 * 0.75)

HashMap的Resize方法具体做了什么事情?

1.扩容
创建一个新的Entry空数组,长度是原数组的2倍。

2.ReHash
遍历原Entry数组,把所有的Entry重新Hash到新数组。为什么要重新Hash呢?因为长度扩大以后,Hash的规则也随之改变。

让我们回顾一下Hash公式:
index = HashCode(Key) & (Length - 1)

当原数组长度为8时,Hash运算是和111B(代表二进制的7)做与运算;新数组长度为16,Hash运算是和1111B(代表二进制的15)做与运算。Hash结果显然不同

ReHash的Java代码如下:

/*** Transfers all entries from current table to newTable.*/
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];newTable[i] = e;e = next;}}
}

注意HashMap在多线程下的Rehash可能会出现什么样的问题呢?

假设一个HashMap已经到了Resize的临界点。此时有两个线程A和B,在同一时刻对HashMap进行Put操作:

此时达到Resize条件,两个线程各自进行Rezie的第一步,也就是扩容:

这时候,两个线程都走到了ReHash的步骤。让我们回顾一下ReHash的代码:

假如此时线程B遍历到Entry3对象,刚执行完红框里的这行代码,线程就被挂起。
于线程B来说
: e = Entry3 next =Entry2
这时候线程A畅通无阻地进行着Rehash,当ReHash完成后,结果如下(图中的e和next,代表线程B的两个引用):

直到这一步,看起来没什么毛病。接下来线程B恢复,继续执行属于它自己的ReHash。
线程B刚才的状态是:e = Entry3 next = Entry2

当执行到上面这一行时,显然 i = 3,因为刚才线程A对于Entry3的hash结果也是3。

我们继续执行到这两行,Entry3放入了线程B的数组下标为3的位置,并且e指向了Entry2。
此时e和next的指向如下:
e =Entry2 next = Entry2
整体情况如下图所示:

接着是新一轮循环,又执行到红框内的代码行:

e = Entry2
next = Entry3
整体情况如图所示:

接下来执行下面的三行,用头插法把Entry2插入到了线程B的数组的头结点:

整体情况如图所示:

第三次循环开始,又执行到红框的代码:

e = Entry3
next = Entry3.next = null

最后一步,当我们执行下面这一行的时候,见证奇迹的时刻来临了

newTable[i] = Entry2
e = Entry3
Entry2.next = Entry3
Entry3.next = Entry2
链表出现了环形!
整体情况如图所示:

此时,问题还没有直接产生。当调用Get查找一个不存在的Key,
而这个Key的Hash结果恰好等于3的时候,由于位置3带有环形链表,所以程序将会进入死循环!

这种情况,不禁让人联想到一道经典的面试题:
漫画算法:如何判断链表有环?
如何杜绝这种情况?

总结如下

1.Hashmap在插入元素过多的时候需要进行Resize,
Resize的条件是 HashMap.Size >= Capacity * LoadFactor。

2.Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环

链表头插法的会颠倒原来一个散列桶里面链表的顺序。在并发的时候原来的顺序被另外一个线程a颠倒了,而被挂起线程b恢复后拿扩容前的节点和顺序继续完成第一次循环后,又遵循a线程扩容后的链表顺序重新排列链表中的顺序,最终形成了环。

Java面试题:高并发环境下,jdk7 HashMap可能出现的致命问题。注意:是在jdk7与及以下版本相关推荐

  1. java支付宝支付_Java 高并发环境下的性能优化,揭秘支付宝技术内幕

    前言 高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等. 为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适 ...

  2. 高并发环境下如何优化Tomcat性能?看完我懂了!

    来自:冰河技术 写在前面 Tomcat作为最常用的Java Web服务器,随着并发量越来越高,Tomcat的性能会急剧下降,那有没有什么方法来优化Tomcat在高并发环境下的性能呢? Tomcat运行 ...

  3. 【高并发】在高并发环境下该如何构建应用级缓存?

    来自:冰河技术 写在前面 随着我们的系统负载越来越高,系统的性能就会有所下降,此时,我们可以很自然地想到使用缓存来解决数据读写性能低下的问题.但是,立志成为资深架构师的你,是否能够在高并发环境下合理并 ...

  4. oom 如何避免 高并发_【高并发】高并发环境下如何防止Tomcat内存溢出?看完我懂了!!...

    [高并发]高并发环境下如何防止Tomcat内存溢出?看完我懂了!! 发布时间:2020-04-19 00:47, 浏览次数:126 , 标签: Tomcat 写在前面 随着系统并发量越来越高,Tomc ...

  5. 在高并发环境下该如何构建应用级缓存

    摘要:立志成为资深架构师的你,是否能够在高并发环境下合理并且高效的构建应用级缓存呢? 本文分享自华为云社区<[高并发]在高并发环境下该如何构建应用级缓存?>,作者:冰 河. 随着我们的系统 ...

  6. tomcat 请求超时_高并发环境下如何优化Tomcat性能?看完我懂了!

    来自:冰河技术 写在前面 Tomcat作为最常用的Java Web服务器,随着并发量越来越高,Tomcat的性能会急剧下降,那有没有什么方法来优化Tomcat在高并发环境下的性能呢? Tomcat运行 ...

  7. 【高并发】高并发环境下构建缓存服务需要注意哪些问题?我和阿里P9聊了很久!

    写在前面 周末,跟阿里的一个朋友(去年晋升为P9了)聊了很久,聊的内容几乎全是技术,当然了,两个技术男聊得最多的话题当然就是技术了.从基础到架构,从算法到AI,无所不谈.中间又穿插着不少天马行空的想象 ...

  8. 【高并发】高并发环境下构建缓存服务需要注意哪些问题?我和阿里P9聊了很久!...

    写在前面 周末,跟阿里的一个朋友(去年晋升为P9了)聊了很久,聊的内容几乎全是技术,当然了,两个技术男聊得最多的话题当然就是技术了.从基础到架构,从算法到AI,无所不谈.中间又穿插着不少天马行空的想象 ...

  9. 高并发环境下,6个构建缓存服务需要注意的问题

    摘要:高并发环境下如何构建缓存服务,你知道吗? 本文分享自华为云社区<[高并发]高并发环境下构建缓存服务需要注意哪些问题?>,作者:冰 河. 缓存特征 (1)命中率:命中数/(命中数+没有 ...

  10. 如何在高并发环境下设计出无锁的数据库操作(Java版本) 转载

    一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...

最新文章

  1. java处理中文字符_Java中文字符处理的四大迷题
  2. mysql 获取当前整点_Oracle 生成未来三天的整点时间(步骤详解)
  3. H2DBEngine——Driver的设计与实现
  4. 米老鼠想吞并喜羊羊,不是赤裸裸的文化侵略是什么
  5. jcmd:JDK14中的调试神器
  6. CentOS安装fortune+cowsay
  7. 在jQuery和JavaScript中,实现转跳
  8. 深入一致性哈希(Consistent Hashing)算法原理
  9. 大表ddl工具online-schema-change使用
  10. 【斐波那契】【前缀和】无限序列
  11. suse配置dhcp服务器
  12. 三次握手与accept()函数
  13. 相册批量下载 前版本为v3.5 支持:雅虎相册、谷歌相册、网易相册、yupoo相册、百度相册、QQ相册
  14. 怎么样学习Java?
  15. 软件智能:aaas系统中AI众生的“世”和“界” 之8-神经系统的假设assumption
  16. Ubuntu/Windows配置AlphaPose填坑(亲测有效)
  17. 关于在li中使用阿里巴巴icon font导致文字不对齐的问题
  18. pytorch指定版本更新
  19. java并发-ReentrantReadWriteLock读写锁
  20. unity3D之简单的碰撞检测 .

热门文章

  1. 解决ModuleNotFoundError: No module named ‘_curses‘错误
  2. 二叉搜索树的思想,以及增删查改的实现
  3. Linux lvs 的固定访问
  4. CentOS6.5+Python2.7+ GIT +IPython
  5. redis队列(list)
  6. Python 模块学习
  7. .net研发工程师面试题,在线交流答案
  8. 分享Silverlight/WPF/Windows Phone一周学习导读(12月20日-12月26日)
  9. 普通域用户设置共享文件夹
  10. 微服务之springCloud-docker-feign配置(五)