原来,JDK8的ConcurrentHashMap也会造成CPU 100%

Posted 占小狼的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原来,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呢?首先我们来运行一下这段代码:

 
   
   
 
  1. Map<String, String> map = new ConcurrentHashMap<>();


  2. map.computeIfAbsent("AaAa", 
     

    key -> map.computeIfAbsent("BBBB", key2 -> "value"));

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

原来,JDK8的ConcurrentHashMap也会造成CPU 100%

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

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

 
   
   
 
  1. map.computeIfAbsent("AaAa", (String key) > {map.put("BBBB", "value"); return "value"; });

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

 
   
   
 
  1. static Map<Integer, Integer> concurrentMap = new ConcurrentHashMap<>();

  2. public static void main(String[] args) {    

  3.  System.out.println("Fibonacci result for 20 is" + fibonacci(20));}

  4.  static int fibonacci(int i) {    

  5.    if (== 0) return i;    

  6.    if (== 1)  return 1;    

  7.    return concurrentMap.computeIfAbsent(i, (key) > {

  8.        System.out.println("Value is " + key);

  9.        return fibonacci(- 2) + fibonacci(- 1); 

  10.   });

  11. }

至于为什么会发生这个BUG,答案就在ConcurrentHashMap中的computeIfAbsent方法中。

如何规避这个问题呢?升级JDK(这个在公司实施有点难),所以要避免在递归中使用computeIfAbsent方法。


-END-

 近期热文:






以上是关于原来,JDK8的ConcurrentHashMap也会造成CPU 100%的主要内容,如果未能解决你的问题,请参考以下文章

ConcurrentHashMap数据结构(jdk8)

jdk8中的ConcurrentHashMap究竟为啥高效?

ConcurrentHashMap的computeIfAbsent方法在jdk8的bug

详解ConcurrentHashMap及JDK8的优化

HashMap与ConcurrentHashMap面试要点

Java | JDK8下的ConcurrentHashMap#putValue