专栏首页Java架构师进阶不止JDK7的HashMap,JDK8的ConcurrentHashMap也会造成CPU 100%

不止JDK7的HashMap,JDK8的ConcurrentHashMap也会造成CPU 100%

大家可能都听过JDK7中的HashMap在多线程环境下可能造成CPU 100%的现象,这个由于在扩容的时候put时产生了死链,由此会在get时造成了CPU 100%。这个问题在JDK8中的HashMap获得了解决。其实JDK7中的HashMap在多线程环境下不止只有CPU 100%这一共怪异现象,它还可能造成插入的数据丢失,有兴趣的读者可以自行了解下。

对于HashMap多线程的问题,我们通常会这么反问:HashMap设计上就不是多线程安全的,何必要去在多线程环境下用呢?的确如此,我们不会傻到显式的在多线程环境下调用,但是又可能在你所关注的视角范围外是多线程的,其隐式地让HashMap置于多线程环境下了,这个又难以一下子察觉到。再者,对于HashMap多线程的问题,我们很多时候推荐使用ConcurrentHashMap来代替HashMap应用于多线程的环境,很不巧的是ConcurrentHashMap也有可能会造成CPU 100%的异常现象。这个怪异现象存在于JDK8的ConcurrentHashMap中,在JDK9中已经得到修复,可以参见:

https://bugs.openjdk.java.net/browse/JDK-8062841

什么情况下JDK8的ConcurrentHashMap会出现这个Bug呢?首先我们来运行一下这段代码:

你会惊奇的发现这个程序一直处于Running状态,我们通过top -Hp [pid]命令查看到其中一个线程的CPU使用率接近100%,参考下图:

可以看到pid为31417的东东,我们再通过jstack -l [pid]命令查看到对应的线程为:

注意将nid=0x7ab9的16进制转为10进制就是31417。可以看到问题是发生在了computeIfAbsent方法中,我们将示例中的程序换成下面这段程序也会同样出现CPU 100%的Bug:

问题的关键在于递归使用了computeIfAbsent方法,笔者在stackoverflow上还搜索到了同类型的问题,下面的示例程序中调用fibonacci方法同样也会造成CPU 100%.

至于为什么会发生这个BUG,答案就在ConcurrentHashMap中的computeIfAbsent方法中,自己去捞吧,嘿嘿。或者等以后的文章。怎么规避这个问题呢?只要不在递归中使用computeIfAbsent方法就好啦,或者降级用可爱的分段锁,或者升级JDK9。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 不止 JDK7 的 HashMap ,JDK8 的 ConcurrentHashMap 也会造成 CPU 100%?原因与解决~

    大家可能都听过JDK7中的HashMap在多线程环境下可能造成CPU 100%的现象,这个由于在扩容的时候put时产生了死链,由此会在get时造成了CPU 10...

    芋道源码
  • 理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略

    (2)在(1)的基础上,理解ConcurrentHashMap的并发安全的设计和实现思路

    我是攻城师
  • BTA 常问的 Java基础40道常见面试题及详细答案

    最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。

    搜云库
  • 详解ConcurrentHashMap及JDK8的优化

    由于HashMap在并发中会出现一些问题,所以JDK中提供了并发容器ConcurrentHashMap。有关HashMap并发中的问题和原理,强烈建议查看这篇文...

    全菜工程师小辉
  • 如何阅读jdk源码?

    这篇文章主要讲述jdk本身的源码该如何阅读,关于各种框架的源码阅读我们后面再一起探讨。

    彤哥
  • 还在为怎么阅读 JDK 源码犯愁吗?

    这篇文章主要讲述jdk本身的源码该如何阅读,关于各种框架的源码阅读我们后面再一起探讨。

    zhisheng
  • 我是这样给阿里面试官吹 ConcurrentHashMap的

    因为上篇文章HashMap已经讲解的很详细了,因此此篇文章会简单介绍思路,再学习并发HashMap就简单很多了,上一篇文章中我们最终知道HashMap是线程不安...

    浅羽技术
  • JDK容器类Map源码解读

    java.util.Map接口是JDK1.2开始提供的一个基于键值对的散列表接口,其设计的初衷是为了替换JDK1.0中的java.util.Dictionary...

    CodingDiray
  • 还看不懂JDK7 HashMap环的产生原理你来打我

    JDK7中当我们用头插法 对旧table数据重定位到新table的时候我们知道是会行程环的,环产生的核心函数transfer如下,其中重点关注部分以标出。

    sowhat1412

扫码关注云+社区

领取腾讯云代金券