hashmap死循环示例及检测方法

原创 2016年08月13日 16:39:27

以前的游戏项目经常使用map作为缓存容器,但由于有些开发人员并发处理意识不强,在多线程环境上误用了线程不安全的HashMap对象,导致死循环发生。一旦发生了死循环,cpu就会暴涨,非重启服务不能解决(=。 =)

众所周知,jdk提供的HashMap类属于线程不安全容器,只能在单线程环境使用,如果在多线程环境下使用可能造成数据丢失,rehash加倍扩容,最严重还会导致死循环。所以在并发环境一定要使用安全容器ConcurrentHashMap。

死循环是怎么发生的呢?简单的说,就是落在同一个hash冲突链的两个元素在多线程扩容情况下出现了环形节点。不管是JDK1.8以前版本基于数组桶+链表的实现,还是JDK1.8基于数组桶+链表/红黑树的实现,都有可能发生死循环。具体的原因分析可参考(hashmap死循环原因

下面先演示一段hashmap死循环的例子,然后说明如何使用jdk提供的工具——jstack,来定位出现问题的代码


一、死循环代码示例(JDK1.7环境)

package demo;

import java.util.HashMap;

public class HashMapTest{  
	private HashMap<Integer,Integer> map = new HashMap<>(); 

	public HashMapTest(){
		Thread t1 = new Thread() {  
			public void run() {  
				for (int i = 0; i < 50000; i++) {  
					map.put(new Integer(i), Integer.valueOf(i));  
				}  
			}  
		};  
		Thread t2 = new Thread() {  
			public void run() {  
				for (int i = 0; i < 50000; i++) {  
					map.put(new Integer(i),Integer.valueOf(i));  
				}  
			}  
		};  
		t1.start();  
		t2.start();  
	}  

	public static void main(String[] args) {  
		new HashMapTest();  
	}  
} 
死循环的概率还是非常低的,比较难以重现。为了提高出现概率,采用多次迭代测试。

写个简单的shell脚本(run.sh),循环次数写大点,如下所示:

#!/bin/bash
for i in `seq 1 10000`; do  
    echo $i
    java demo.HashMapTest
done  
  
exit 0
脚本唯一的作用就是多次运行java代码。为了清楚感知程序已经发生了死循环,在每次迭代中输出当前的迭代次数。一旦迭代输出停止了,就说明死循环出现了。

在控制台执行脚本,命令为"./run.sh",然后上个厕所,喝杯茶……

我运气还是蛮好的,回来的时候已经发生了死循环,如下图(卡住在第55次迭代)



二、jstack定位问题

出现了死循环后,我们可以使用jstack命令来定位问题

1.查找jvm进程id (pid=23199)

ps -ef| grep java


2.查找发生死循环的线程id(threadId=23214),cpu利用率暴表的第一条记录就是了。将十进制23214转为十六进制5aae

top -Hp 23199

3.使用jstack导出thread dump信息

jstack -l 23199 > ~/threaddump.txt

4.分析dump数据,查找cpu最高的线程的运行堆栈。可以看出,死循环发生在hashmap的put()方法。

cat threaddump.txt |grep -A10 5aae




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Java HashMap的死循环

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、...

hashmap死循环原因总结

本文受http://pt.alibaba-inc.com/wp/dev_related_969/hashmap-result-in-improper-use-cpu-100-of-the-proble...

并发的HashMap为什么会引起死循环?

今天研读Java并发容器和框架时,看到为什么要使用ConcurrentHashMap时,其中有一个原因是:线程不安全的HashMap, HashMap在并发执行put操作时会引起死循环,是因为多线程会...

HashMap多线程死循环问题

正如上篇文中所说,HashMap不是线程安全的,在被多线程共享操作时,会有问题,具体什么问题呢,一直没有个清晰的理解,今天写了个测试程序调了一下,才明白其中道理。 主要是多线程同时put时,如果同时触...

jdk1.8 hashmap多线程put不会造成死循环

jdk1.8 hashmap多线程put不会造成死循环

HTML5安全风险详析之一:CORS攻击

一、从SOP到CORS        SOP就是Same Origin Policy同源策略,指一个域的文档或脚本,不能获取或修改另一个域的文档的属性。也就是Ajax不能跨域访问,我们之前的Web资源...
  • hfahe
  • hfahe
  • 2012年09月09日 22:28
  • 10808

canvas画矩形之清除,描边与填充

--> Rectangles body { background: #dddddd; } ...

图解集合5:不正确地使用HashMap引发死循环及元素丢失

问题引出 前一篇文章讲解了HashMap的实现原理,讲到了HashMap不是线程安全的。那么HashMap在多线程环境下又会有什么问题呢? 几个月前,公司项目的一个模块在线上运行的时候出现...

HashMap死循环及JDK1.8的resize()如何维护链表顺序

HashMap死循环 我第一次听到HashMap会有死循环的问题是两年前,我们团队有一个学长实习回来给我们说有个同事因为没有注意到HashMap在多线程可能会造成死循环而造成了一些损失。后面就对这个...

HashMap 死循环的探究

本文转载自:http://www.iteye.com/topic/962172     本文受http://pt.alibaba-inc.com/wp/dev_related_969/hashm...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hashmap死循环示例及检测方法
举报原因:
原因补充:

(最多只允许输入30个字)