`
shuaijie506
  • 浏览: 136145 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

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

    博客分类:
  • jdk
阅读更多

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

 

       产生这个死循环的根源在于对一个未保护的共享变量 — 一个"HashMap"数据结构的操作。当在所有操作的方法上加了"synchronized"后,一切恢复了正常。

       这算jvm的bug吗?应该说不是的,这个现象很早以前就报告出来了(详细见:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6423457)。Sun的工程师并不认为这是bug,而是建议在这样的场景下应采用"ConcurrentHashMap",

回复中的原话:

This is a classic symptom of an incorrectly synchronized use of
HashMap. Clearly, the submitters need to use a thread-safe
HashMap. If they upgraded to Java 5, they could just use ConcurrentHashMap. 

 

所以在开发过程中应当注意这点,在多线程的环境下,尽量使用ConcurrentHashMap。

可能出现问题的地方是在扩容的时候

void resize(int newCapacity) {  
        Entry[] oldTable = table;  
        int oldCapacity = oldTable.length;  
        if (oldCapacity == MAXIMUM_CAPACITY) {  
            threshold = Integer.MAX_VALUE;  
            return;  
        }  
  
        Entry[] newTable = new Entry[newCapacity];  
        transfer(newTable);  
        table = newTable;  
        threshold = (int)(newCapacity * loadFactor);  
    }  

 这个方法本身没有问题,问题出在transfer(newTable);这个方法是用来移动oldTable里的数据到newTable里。

/** 
    * Transfers all entries from current table to newTable. 
    */  
   void transfer(Entry[] newTable) {  
       Entry[] src = table;  
       int newCapacity = newTable.length;  
       for (int j = 0; j < src.length; j++) {  
        //(1)  
           Entry<K,V> e = src[j];  
           if (e != null) {  
               src[j] = null;  
               do {  
                //(2)  
                   Entry<K,V> next = e.next;  
                   int i = indexFor(e.hash, newCapacity);  
                //(3)  
                   e.next = newTable[i];  
                   newTable[i] = e;  
                   e = next;  
               } while (e != null);  
           }  
       }  
   }  

 下面分析可能出现的情况,假设原来oldTable里存放a1,a2的hash值是一样的,那么entry链表顺序是:

P1:oldTable[i]->a1->a2->null

P2:oldTable[i]->a1->a2->null

线程P1运行到(1)下面这行时,e=a1(a1.next=a2),继续运行到(2)下面时,next=a2。这个时候切换到线程P2,线程P2执行完这个链表的循环。如果恰a1,a2在新的table中的hash值又是一样的,那么此时的链表顺序是: 

主存:newTable[i]->a2->a1->null

注意这个时候,a1,a2连接顺序已经反了。现在cpu重新切回P1,在(3)这行以后:e.next = newTable[i];即:a1.next=newTable[i];

newTable[i]=a1;

e=a2;

开始第二次while循环(e=a2,next=a1):

a2.next=newTable[i];//也就是a2.next=a1

newTable[i]=a2

e=a1

开始第三次while循环(e=a1,next=null)

a1.next=newTable[i];//也就是a1.next=a2

 

这个时候a1.next=a2,a2.next=a1,形成回环了,这样就造成了死循环,在get操作的时候next永远不为null,造成死循环。

可以看到很偶然的情况下会出现死循环,不过一旦出现后果是非常严重的,多线程的环境还是应该用ConcurrentHashMap。

 

分享到:
评论
2 楼 lwclover 2013-08-05  
hashmap不是线程安全的,jdk文明规定。。。。
1 楼 wangwangten 2013-06-09  
感谢lz的帮助 本来程序中用hashmap是用来统计一大堆数据中的不重复项的 想着hashmap不同步大不了就覆盖了刚写的项呗,反正是一样的数据, 结果CPU不一会上了100%就下不来了,费了老大劲找原因。

相关推荐

    Java面试题-并发.docx

    接着,文档讨论了负载因子的概念及其取值为0.75的原因,以及HashMap在多线程环境下的线程安全性问题,指出了可能导致CPU利用率达到100%的并发扩容问题,并提出了解决方案。 此外,文档介绍了哈希冲突的概念和解决...

    Java面试题-哈希.docx

    接着,文件讨论了负载因子的概念及其取值为0.75的原因,以及HashMap在多线程环境下的线程安全性问题,指出了可能导致CPU利用率达到100%的并发扩容问题,并提出了解决方案。 此外,文件介绍了哈希冲突的概念和解决...

    java7hashmap源码-lf-study-java-multithreading:华东师范及马士兵多线程,项目主要介绍java多线程以及

    java多线程和多进程 以下内容包含:华东师范大学的多线程讲解 及 马士兵多线程讲解 马士兵多线程讲解迁移位置:仓库 DOCRecord\ResteasyComplexDemo\src\pers\lishbo\timetask 1.多进程: 1.当前的操作系统都是多...

    java7hashmap源码-java-concurrency-programming:java并发编程入门

    同时拥有俩个或者多个线程,如果线程在单核处理器上运行,多个线程将交替的换入或者换出内存,这些线程是同时 "存在" 的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上,此时程序中的每个线程都将...

    java7hashmap源码-Concurrency:java高并发编程

    多线程模块: 并发的基本概念: 同时拥有一个或者多个线程,如果程序在单核处理器上运行,多个线程将交替的换入或者换出内存。 一个线程对应者Cpu的一个内核。现在系统都是多核处理器,同时支持多个并发一起执行程序...

    疫苗:Java HashMap的死循环

    在淘宝内网里看到同事发了贴说了一个CPU被的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历过,本来觉得没什么好写的,...

    飞机游戏java源码-DesignSystem:设计系统

    3)什么是多线程中的上下文切换? 4)死锁和活锁、死锁和饥饿的区别? 5) Java 中使用了什么线程调度算法? 6) Java 中的线程调度器是什么? 7) 如何处理线程中未处理的异常? 8) 什么是线程组,为什么不建议在 Java...

    java面试题

    51.3. 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 24 51.4. 线程同步的方法。 24 51.5. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 25...

    招银网络java科技笔试题-mianjing:mianjing

    多线程问题? concurrentHashMap?读写操作实现?锁机制?实现维持map大小的LRU算法? volatile关键字?volatile修饰数组?修饰对象? 找两条链表公共节点? 如何判断循环链表? mysql索引?B+数搜索复杂度? mysql...

    java核心知识点整理.pdf

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    阿里P7面试题整理集合

    1)多线程(ThreadLocal(问了父子线程怎么共享数据 interitableThreadLocals)、lock和sync区别(问HashMap1.7、1.8区别时带出)、 AQS原理(执行过程源码,入队出队的细节,源码细节)、CountDownLatch和 ...

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    leetcode下载-Note:我的笔记

    多线程和线程池 HTTP、HTTPS、TCP/IP、Socket通信、三次握手四次挥手过程 设计模式(六大基本原则、项目中常用的设计模式、手写单例等) 断点续传 volatile理解,JMM中主存和工作内存到底是啥?和JVM各个部分怎么个...

Global site tag (gtag.js) - Google Analytics