`

HashMap-死锁导致cpu占用100%分析

 
阅读更多
最近项目里面的一段千年代码出了问题,这个问题以前也出现过,不过不是那么明显,这次迁移机器由以前的4台机子变成2台以后问题被放大,最终不得不解决,特此分析一下。



先放出问题的代码

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


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。



线上观察很多天,一切正常。
分享到:
评论

相关推荐

    线程死锁CPU过高,请求原因分析

    线程死锁是多线程编程中一个严重的问题,它发生在两个或多个线程相互等待对方释放资源,导致它们都无法继续执行。CPU过高通常与过度的计算、无尽循环、死锁、线程竞争状态等问题相关。在Java编程中,WeakHashMap是一...

    Java Interview Questions/Java面试题

    - 性能分析:JProfiler、VisualVM等工具的使用,进行内存泄漏、CPU瓶颈等诊断。 7. **设计模式** - 单例模式:懒汉式、饿汉式、双重检查锁定等实现方式。 - 工厂模式:简单工厂、工厂方法、抽象工厂。 - 适配器...

    Java性能调优PPT

    - **线程不安全示例**:使用`HashMap`时,在多线程环境下可能导致数据不一致,进而导致CPU占用率异常升高。 - **死锁案例分析**:例如Spring框架中的死锁问题,通常需要仔细分析代码逻辑才能发现和解决。 #### 结语...

    Java 性能分析

    - **JProfiler**:一款强大的商业Java性能分析器,包括CPU、内存、线程、Garbage Collection等多种分析功能。 2. **第三方工具**: - **YourKit Java Profiler**:提供深入的内存和CPU分析,帮助定位性能瓶颈。 ...

    黑马面试题总结

    - `Thread.sleep()`方法导致当前线程暂停执行指定的时间,不会释放对象锁。 - `Object.wait()`方法则使线程等待直到另一个线程唤醒它或者超时,会释放对象锁。 - **线程生命周期:** - **新建状态(New)**:创建...

    Java经典问题答案(带书签).pdf

    - 垃圾回收(GC)是Java的一项自动化内存管理功能,负责回收不再使用的对象所占用的内存。 - Java的GC算法包括标记-清除算法、复制算法、标记-整理算法等。 **==与equals的区别** - `==`用于比较引用是否指向同一个...

    java面试宝典题

    每种数据类型都有其固定的内存占用大小。 - **Byte**: 占用1个字节,范围从-128到127。 - **Short**: 占用2个字节,范围从-32768到32767。 - **Int**: 占用4个字节,是最常用的整型数据类型。 - **Long**: 占用8个...

    Java多线程文章系列.pdf

    实际上,即使只有一个CPU,也可以通过快速切换实现并发效果。 ##### 2. 在Java中实现多线程 - **实现方式**: 在Java中实现多线程只需要提供线程将要执行的代码。 - **实现步骤**: - 继承`java.lang.Thread`类或...

    WebLogic开发优化宝典

    - 选择非同步容器,如ArrayList和HashMap,它们在多线程环境下性能更优。 1.1.4 使用资源池、缓冲区和缓存: - 数据库连接池(如WebLogic的JDBC Connection Pool)、Socket Pool、Object Pool和Thread Pool能有效...

    javase全套笔记.zip

    - **线程调度**:Java采用分时调度模型,每个线程轮流占用CPU资源。 - **线程间通信**:wait()、notify()、notifyAll()方法用于实现线程间的同步和通信。 - **死锁**:多个线程相互等待对方持有的锁,从而导致所有...

    Java程序性能优化 让你的Java程序更快、更稳定

    - **使用Profiler工具**:如VisualVM、JProfiler等,分析CPU、内存和线程状况,找出性能瓶颈。 9. **代码重构** - **简化代码**:消除冗余代码,减少不必要的计算和逻辑复杂性。 - **模块化设计**:提高代码...

    Java经典面试题+答案(带书签)pdf

    - 这样的设计有助于减少内存占用,提高性能。 **8. 构造代码块和构造函数的区别** - **构造代码块**:每次创建对象时都会执行,位于类体中。 - **构造函数**:用于初始化对象的状态,每次创建对象时调用。 **9. ...

    线程面试汇总.docx

    但是,如果持有自旋锁的时间过长,可能导致其他等待线程长时间占用CPU资源,进而引起CPU使用率上升。因此,在使用自旋锁时,需要特别注意锁的持有时间,并且在进入休眠前释放锁。 ### Java内存模型 - **Java内存...

    经典的问题

    - Java自动管理内存,通过垃圾回收器定期回收不再使用的对象所占用的内存。 **12. ==与equals的区别** - `==`: 用于比较基本类型值或引用类型变量是否指向同一对象。 - `equals`: 用于比较对象的内容是否相同。 *...

    java经典面试题

    - 执行:占用 CPU。 - 阻塞:等待某一事件完成。 5. **IPC 几种通信方式**: - 管道:允许父子进程之间的通信。 - 消息队列:允许发送消息到接收者。 - 信号量:管理多个进程对共享资源的访问。 - 共享内存:...

    计算机&软件工程&人工智能研究生复试资料整理

    - **不推荐使用stop()和suspend()方法**:可能导致数据不一致和死锁。 - **sleep()和wait()的区别**:`sleep()`不会释放锁,`wait()`会释放锁并等待通知。 - **线程同步概念**:防止多个线程同时访问共享资源导致...

    Java面试宝典

    6. **避免N个线程访问N个资源导致死锁的方法** - 确保每个线程按照相同的顺序获取资源。 - 使用超时机制尝试获取锁。 - 设计系统时尽量减少共享资源的使用。 7. **`sleep()`与`wait()`的区别** - `sleep()`是`...

    Java语言的银行家算法.rar-综合文档

    在计算机系统中,这对应于分配系统资源(如内存、磁盘空间、CPU时间等)时,确保系统安全,避免资源耗尽导致的死锁。 2. **资源与需求** 在银行家算法中,每个进程都有一个最大需求,表示它可能需要的最大资源量;...

Global site tag (gtag.js) - Google Analytics