java中HashMap在多线程环境下引起CPU100%的问题解决(转)
最近项目中出现了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。
http://shuaijie506.iteye.com/blog/1815213
http://blog.163.com/huxb23%40126/blog/static/625898182011211318854/
java中HashMap在多线程环境下引起CPU100%的问题解决(转)的更多相关文章
- java中HashMap在多线程环境下引起CPU100%的问题解决
最近项目中出现了Tomcat占用CPU100%的情况,原以为是代码中出现死循环,后台使用jstack做了dump,发现是系统中不合理使用HashMap导致出现了死循环(注意不是死锁). 产生这个死循环 ...
- 你是否听说过 HashMap 在多线程环境下操作可能会导致程序死循环?
作者:炸鸡可乐 原文出处:www.pzblog.cn 一.问题描述 经常有些面试官会问,是否了解过 HashMap 在多线程环境下使用时可能会发生死循环,导致服务器 cpu 100% 的线上故障? 关 ...
- Java之HashMap在多线程情况下导致死循环的问题
PS:不得不说Java编程思想这本书是真心强大.. 学习内容: 1.HashMap<K,V>在多线程的情况下出现的死循环现象 当初学Java的时候只是知道HashMap<K,V& ...
- Java指令重排序在多线程环境下的应对策略
一.序言 指令重排在单线程环境下有利于提高程序的执行效率,不会对程序产生负面影响:在多线程环境下,指令重排会给程序带来意想不到的错误. 本文对多线程指令重排问题进行复原,并针对指令重排给出相应的解决方 ...
- java中HashMap原理?
参考:https://www.cnblogs.com/yuanblog/p/4441017.html(推荐) https://blog.csdn.net/a745233700/article/deta ...
- HttpClient在多线程环境下踩坑总结
问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态. 而且,从程序日志中判断有线程处于han ...
- Java中HashMap底层原理源码分析
在介绍HashMap的同时,我会把它和HashTable以及ConcurrentHashMap的区别也说一下,不过本文主要是介绍HashMap,其实它们的原理差不多,都是数组加链表的形式存储数据,另外 ...
- java中HashMap的设计精妙在哪?
摘要:本文结合图解和问题,教你一次性搞定HashMap 本文分享自华为云社区<java中HashMap的设计精妙在哪?用图解和几个问题教你一次性搞定HashMap>,作者:breakDaw ...
- C#多线程环境下调用 HttpWebRequest 并发连接限制
C#多线程环境下调用 HttpWebRequest 并发连接限制 .net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 win ...
随机推荐
- Deep Learning深入研究整理学习笔记五
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- ASP.NET - 记录错误日志
不需要像log4net/Nlog/Common Logging配置,简单好用. 不用增加声明logger对象,可记录当前执行状况. 可以定义 维护功能模板的开发人员,以便用功能模块对于开发人员. 出处 ...
- Beautiful Soup 中文文档
Beautiful Soup 3.0 中文文档说明: http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html Be ...
- python发送post和get请求
python发送post和get请求 get请求: 使用get方式时,请求数据直接放在url中. 方法一. import urllib import urllib2 url = "http: ...
- cPickle.so:: PyUnicodeUCS2_DecodeUTF8
cPickle.so:: PyUnicodeUCS2_DecodeUTF8错误 Python编译的参数,和Python module(mod_wsgi, pymodwsgi)编译参数不一,导致一些un ...
- 【ASP.NET Web API教程】2.3.3 创建Admin控制器
原文:[ASP.NET Web API教程]2.3.3 创建Admin控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 3 ...
- DAG上的动态规划
嵌套矩形问题(最长路及其字典序)有n个举行,选出尽量多的矩阵排成一排,使得除了最后一个之外,每一个矩形可以嵌套在下一个矩形内,并且打印 #include <iostream> #inclu ...
- MyBATIS使用CRUD
MyEclipse不提供自己主动生成,这里提供mybatis文件包和开发文档 http://download.csdn.net/detail/u010026901/7489319 自己建立配置文件, ...
- ISO/OSI网络体系结构和TCP/IP协议模型
1. ISO/OSI的参考模型共有7层,由低层至高层分别为:物理层.数据链路层.网络层.传输层.会话层.表示层. 应用层.各层功能分别为: (1)物理层 提供建立.维护和拆除 ...
- linux route命令的使用详解
route命令用于显示和操作IP路由表.要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现.在Linux系统中,设置路由通常是 为了解决以下问题:该Linu ...