最近项目里面的一段千年代码出了问题,这个问题以前也出现过,不过不是那么明显,这次迁移机器由以前的4台机子变成2台以后问题被放大,最终不得不解决,特此分析一下。
先放出问题的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
private AlimamaCodeDAO alimamaCodeDAO; private Cache cache; /** * @param cache the cache to set */ public void setCache(Cache cache) { this .cache = cache; } private Map codeMap; // KEYCODE与KEYNAME public List<AlimamaCodeDO> getAlimamaCodeByKey(String key) throws BOException { initCodeMap(); return (List<AlimamaCodeDO>) codeMap.get(key); } private void initCodeMap() throws BOException { try { //Element element = cache.get(CacheKeyConstants.ALIMAMACODE_KEY); //if (element == null) { List codes = alimamaCodeDAO.findAllAlimamaCode(); codeMap = new HashMap(); for ( int i = 0 ; i < codes.size(); i++) { AlimamaCodeDO codeDo = (AlimamaCodeDO) codes.get(i); if (!codeMap.containsKey(codeDo.getKey())) { List list = new ArrayList(); list.add(codeDo); codeMap.put(codeDo.getKey(), list); } else { ((List) codeMap.get(codeDo.getKey())).add(codeDo); } } //element = new Element(CacheKeyConstants.ALIMAMACODE_KEY, (Serializable) codeMap); //cache.put(element); //} //codeMap = (Map) element.getValue(); } catch (DAOException e) { throw new BOException( "获取系统编码表时出现异常" , e); } } |
这一段代码有点漏洞百出,在调用getAlimamaCodeByKey的时候,高并发下,会出现hashmap的死锁,导致cpu100%。至于这个代码为什么写出这样,就暂时不叙述了,就来分析一下出现死锁的原因是什么。
每一次调用getAlimamaCodeByKey的时候,首先是去初始化这个hashmap,在初始化时,这个hashmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for ( int j = 0 ; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null ) { src[j] = null ; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null ); } } } |
死锁就出现在了while (e != null);从上面的代码看来,每一个线程进来都先执行 codeMap = new HashMap();这个时候codeMap是空的,所以在执行下面的操作的时候进入了某一个不可以随意
更改状态的代码中,再加上高并发,一直被new HashMap(),while一直被执行,变成了死循环。cpu就瞬间飙升到100%,一直持续到请求数降低的时候。
最后解决办法:重构这部分代码,这部分代码本来就是写的不正确。再将HashMap改为ConcurrentHashMap,线程安全的Map。
线上观察很多天,一切正常。
http://www.cnblogs.com/Baichuan/archive/2010/12/28/1919001.html