码迷,mamicode.com
首页 > 编程语言 > 详细

生产环境遇到的hashMap非线程安全问题java.lang.thread.waiting

时间:2017-09-16 14:44:25      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:tab   广告   thread   resource   ati   logs   .com   过程   www.   

写在前面:工作有几年了,从入门到现在,遇到也解决了一些问题。(当然,框架级别的暂时还没有)一直以来,都是从博客园以及其他各大社区搜罗出来的各种fix方法。目前稍有闲暇时间,在看过大V沈剑的博文后,我也鼓起勇气来书写博客,记录工作中遇到和解决的问题(其中当然也包括我在博园获取的各种解决方法;能找到原博文的小弟一定会注明出处。)因为总觉得自己水平不够,怕写出来的文章误导了别人。以下是这周生产环境遇到的一个问题,写出来供大家参考。

现象

  周五一大早,车子都没停稳(电动车),群里就开始在询问谁最近的代码有比较耗时耗性能的操作,大家都说没有。然后就是一张截图:

技术分享

cpu已经飙到1600+,这个问题还是比较严重的。随后联系到运维组给出tomcat运行日志排查是否有错误。经过排查日志发下如下错误:

技术分享

看到后飞速坐到位置上,去查询对应的错误代码;

 

分析和搜索:

  以下是部分代码截图:

 1     public static Map<String,String> cityCodeMap = new HashMap<String, String>();
 2     
 3     public static Map<String,String> provinceMap = new HashMap<String, String>();
 4     
 5     public static List<String> sensitiveWordList = new ArrayList<String>();
 6     
 7     public static String getCityCodeByNumber(String phoneNumber)
 8     {
 9         String start = StringUtils.substring(phoneNumber, 0, 7);
10         if(StringUtils.isEmpty(start))
11         {
12             return "000";
13         }
14         Map<String, String> cityCodes = getCityCodes();
15         String cityCode = cityCodes.get(start);
16         if(StringUtils.isEmpty(cityCode))
17         {
18             return "000";
19         }
20         return cityCode;
21     }

 

主要用于获取手机号码的号段对应的城市编码,项目的某个模块(不能打广告吧)需要用到。并且每次调用都用用到;咋一看,感觉没啥问题,项目中好多地方都是这么干的。接着又在测试环境和本地环境跑一边代码,都运行正常。

然后就搜索了java.lang.thread.waiting 这个异常,在这篇博文中搜到相关问题,http://www.cnblogs.com/zhengyun_ustc/archive/2013/03/18/tda.html

才发现可能是多线程引发的问题。

这里列举两个比较解释特别详细的博文,源码跟踪和分析过程都非常详细。

http://coding-geek.com/how-does-a-hashmap-work-in-java/

https://coolshell.cn/articles/9606.html

  

  此种情况虽然是概率发生的,但是在并发量比较大的情况下,还是及其危险的。如果发现不及时,很有可能导致单点故障甚至整个集群不可用。又根据自己项目代码的情况分析,主要是因为在初始化中,循环向map中put新元素导致map扩容rehash时产生了死循环。

初始化代码:

    public static Map<String,String> getCityCodes() {
        if(cityCodeMap.isEmpty())
        {
            Set<String> keySet = ResourceBundle.getBundle("config/citynum").keySet();
            for (String key : keySet) {
                String cityCode = PropertiesUtil.getKey("config/citynum",key);
                cityCodeMap.put(key, cityCode);
            }
        }
        return cityCodeMap;
    }

ps:此处的citynum中有几万个键值对。

解决办法:

  1. Hashtable
  2. ConcurrentHashMap
  3. Synchronized Map

可自行搜索实现原理,很多大神、大仙儿都阐述的比我详细。

都说程序员都是懒人,我不认同。我们只不过是想用最少的代码去解决问题。所以,我们的改良方案就是把HashMap直接换成ConcurrentHashMap

技术分享

 

生产环境遇到的hashMap非线程安全问题java.lang.thread.waiting

标签:tab   广告   thread   resource   ati   logs   .com   过程   www.   

原文地址:http://www.cnblogs.com/xuwangs/p/7531054.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!