当前位置: 首页 > Java > 正文

并发场景下错误使用HashMap的Case

1 星2 星3 星4 星5 星 (2 次投票, 评分: 5.00, 总分: 5)
Loading ... Loading ...
baidu_share

某天中午的时候突然收到一堆报警,有几台机器load过500了,赶紧到机器上排查是什么问题,先top看了下,cpu us接近100%,于是shift h看看线程的状况,发现没什么消耗高的线程,基本都在0.7%左右,但线程总数看起来很多,于是ps -eLf | grep java -c统计了下,总共有700+个线程,连续执行了几次jstack,然后先重启避免故障持续太久,重启完后看起来好了,查看之前jstack出来的线程信息,发现其中有600个线程处于RUNNABLE状态,并且都在执行HashMap.get,根据以往的经验,基本可以确定是在并发场景下错误使用HashMap造成的(关于常见的Java问题的排查方法可见此贴)。

根据堆栈信息找到相应的出问题的类名,然后根据classloader的装载机制(例如web应用通常在应用的war包/WEB-INF/lib下)找到相应的jar,用jd-gui反编译看了下相应的代码,代码中使用此HashMap的方式类似如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class xxxxx{
    private static Map<String,List<String>> caches = new HashMap<String,List<String>>();
    public void load(){
        caches = new HashMap<String,List<String>>();
        // 往此caches放东西
        for...{
            caches.put(...
        }
    }
 
    public List<String> get(String key){
         return caches.get(key);
    }
}

当时堆栈中的信息显示600个线程均在执行caches.get(key),写这段代码的同学之前之所以在这个地方使用HashMap,并且没有加锁,是因为认为load这个方法只会在spring初始化当前这个bean的时候执行一次,但不幸的是后来由于业务发展,这个load方法在数据变更的时候会触发,于是就可能会出现正在往caches里put东西的时候,其他的线程在get,直接就导致并发问题,HashMap.get的并发问题有可能会导致get方法中的下面这段代码进入死循环:

1
2
3
4
5
6
7
for (Entry<K,V> e = table[indexFor(hash, table.length)];
     e != null;
     e = e.next) {
     Object k;
     if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
         return e.value;
}

当然,出现这个现象不是HashMap的问题,主要还是使用的问题,因此这个问题的修复也很容易,就是用ConcurrentHashMap来替换。

这几天又在另外一个应用里造成出现了这个bug,有问题的代码类似如下:

1
2
3
4
5
6
7
8
9
10
11
private static Map...  cache = new HashMap...
 
Object object = cache.get(key);
 
if(object == null){
 
       object = 一个比较耗资源的获取Object动作...
 
       cache.put(key,object);
 
}

这段代码是在并发场景下执行的,因此同样是典型的bug,这段代码改造起来稍微麻烦点,即使是使用ConcurrentHashMap,也需要慎重处理,因此上面的整个动作是非原子性的操作(这个时候通常要引入Future)。

high cpu usage in hashmap.get是Google搜hashmap相关的词中的热词,可见这错误是挺容易犯的,诸如著名的Velocity、Hessian都犯过类似的错。
Hessian老版本中的类似bug:http://bugs.caucho.com/view.php?id=1588
Velocity老版本中的类似bug:https://issues.apache.org/jira/browse/VELOCITY-718

本文固定链接: http://www.chepoo.com/concurrent-error-hashmap-case.html | IT技术精华网

并发场景下错误使用HashMap的Case:等您坐沙发呢!

发表评论