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

写在前面:工作有几年了,从入门到现在,遇到也解决了一些问题。(当然,框架级别的暂时还没有)一直以来,都是从博客园以及其他各大社区搜罗出来的各种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。

时间: 2024-10-25 20:24:27

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

Java 线程--继承java.lang.Thread类实现线程

现实生活中的很多事情是同时进行的,Java中为了模拟这种状态,引入了线程机制.先来看线程的基本概念. 线程是指进程中的一个执行场景,也就是执行流程,进程和线程的区别: 1.每个进程是一个应用程序,都有独立的内存空间. 2.同一个进程中的线程共享其进程中的内存和资源. (共享的内存是堆内存和方法区内存,栈内存不共享,每个线程有自己的栈内存) 我们还需要了解以下基本内容: 1.什么是进程? 一个进程对应一个应用程序.例如:在Windows操作系统启动word就表示启动了一个进程.在Java开发环境下

.进程&amp;线程(&amp;java.lang.Thread)详解

一.进程与线程 进程 我们在进行操作电脑的时候,通常会打开浏览器,通讯工具等应用程序,这个时候CPU通过作业调度在内存中就会分配一些空间让它们处于宏观上的运行状态(处于可以被CPU执行的状态),而这部分空间资源就可以说是相应的进程占据的,很显然运行不同的程序需要不同的进程,在内存中也为它们分配独立,无共享的区域.静态描述进程的是PCB快(数据结构集),它是系统感知进程存在的唯一实体,通常包含进程名(或者标识符),用户名(或者用户标识号),家族关系. 进程的状态 就绪态:进程获得了除cpu以外的其

关于 SimpleDateFormat 的非线程安全问题及其解决方案

1.问题: 先来看一段可能引起错误的代码: package test.date; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class ProveNotSafe { static SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy&qu

java线程安全和非线程安全问题

ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题.面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的:HashMap是非线程安全的,HashTable是线程安全的:StringBuilder是非线程安全的,StringBuffer是线程安全的.因为这是昨晚刚背的<Java面试题大全>上面写的.此时如果继续问:什么是线程安全

【java并发】造成HashMap非线程安全的原因

0. 写在前面 在前面我的一篇总结线程范围内共享数据文章中提到,为了数据能在线程范围内使用,我用了HashMap来存储不同线程中的数据,key为当前线程,value为当前线程中的数据.我取的时候根据当前线程名从HashMap中取即可. 因为当初学习HashMap和HashTable源码的时候,知道HashTable是线程安全的,因为里面的方法使用了synchronized进行同步,但是HashMap没有,所以HashMap是非线程安全的.在上面提到的例子中,我想反正不用修改HashMap,只需要

java 线程栈 &amp; java.lang.StackOverflowError

网上搜索了一下,关于java的线程栈: JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K. JVM的内存,被划分了很多的区域: (来源:http://www.iteye.com/topic/808550) 1.程序计数器 每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令. 2.线程栈 线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表.操作栈.动态链接.方法出入口等信息.每一个方法的调用至完成,就意味着一个帧在VM栈中

验证hashmap非线程安全

http://www.blogjava.net/lukangping/articles/331089.html final HashMap<String, String> firstHashMap = new HashMap<String, String>(); Thread t1=new Thread(){ public void run() { for(int i=0;i<25;i++){ firstHashMap.put(String.valueOf(i), Strin

两个JDK环境下,Tomcat启动时遇到java.lang.UnsatisfiedLinkError

由于最近自己安装了两个jdk环境,然后在启动Tomcat时遇到了启动失败的错误 具体错误: 解决方法: 删除C:\Windows\System32目录下的tcnative-1.dll,这个文件是Tomcat Native Java Library.

Windows下的PHP安装文件线程安全和非线程安全的区别

从2000年10月20日发布的第一个Windows版的PHP3.0.17开始的都是线程安全的版本,这是由于与Linux/Unix系统是采用 多进程的工作方式不同的是Windows系统是采用多线程的工作方式.如果在IIS下以CGI方式运行PHP会非常慢,这是由于CGI模式是建立在多进程 的基础之上的,而非多线程.一般我们会把PHP配置成以ISAPI的方式来运行,ISAPI是多线程的方式,这样就快多了.但存在一个问题,很多常用的 PHP扩展是以Linux/Unix的多进程思想来开发的,这些扩展在IS