摘要:一直都知道Java HashMap使用不当会导致CPU 达到100%的线上故障,以及怎么造成的,怎么在使用过程中进行规避,由于时间的关系。最近整理如本文所示。
一.HashMap出现死循环原因
1.1 什么是线程安全
当多个线程
访问某一个类(对象和方法)时
,这个类的对象或方法
都能始终表现出正确的行为或者我们想要的结果,我们就认为其是线程安全的,否则非线程安全。我们都知道HashMap是非线程安全的,那怎么使用HashMap会导致CPU占用率达到100%。
之所以会导致HashMap出现死循环是因为多线程会导致HashMap的Entry节点形成环链
,这样当遍历集合时Entry的next节点由于不为空
,从而形成死循环,从而导致CPU达到100%
1.2 为何出现死循环简要说明
HashMap是非线程安全的,在高并发场景下,如果不能保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU的消耗到100%。
HashMap采用链表解决Hash冲突。因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环,
单线程情况下,只有一个线程对HashMap的数据结构进行操作,是不可能产生闭合的回路的。
只有在多线程并发的情况下才会出现这种情况,那就是在put操作的时候,如果size>initialCapacity*loadFactor,hash表进行扩容,那么这时候HashMap就会进行rehash操作,随之HashMap的结构就会很大的变化。很有可能就是在两个线程在这个时候同时触发了rehash操作,产生了闭合的回路。
二.HashMap死循环原因分析
2.1 问题的症状
在多线程下使用HashMap,到了线上之后,我们发现程序经常占了100%的CPU,查看堆栈,你会发现程序都Hang在了HashMap.get()这个方法上了,重启程序后问题消失。但是过段时间又会来。而且,这个问题在测试环境里可能很难重现。
2.2 为什么会造成死循环
HashMap采用链表解决Hash冲突,因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环。但是,我好奇的是,这种闭合的链路是如何形成的呢。在单线程情况下,只有一个线程对HashMap的数据结构进行操作,是不可能产生闭合的回路的。那就只有在多线程并发的情况下才会出现这种情况,那就是在put操作的时候,如果size>initialCapacity*loadFactor,那么这时候HashMap就会进行rehash操作,随之HashMap的结构就会发生翻天覆地的变化。很有可能就是在两个线程在这个时候同时触发了rehash
操作,产生了闭合的回路。
三.参考文章
http://blog.csdn.net/xuefeng0707/article/details/40797085
http://coolshell.cn/articles/9606.html
http://firezhfox.iteye.com/blog/2241043
http://www.cnblogs.com/kxdblog/p/4323892.html
http://www.cnblogs.com/ITtangtang/p/3966467.html
http://blog.csdn.net/xuefeng0707/article/details/40797085
http://blog.csdn.net/zhuqiuhui/article/details/51849692