欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DWR bug致使CPU 飙高的原因分析

程序员文章站 2022-05-13 11:20:13
...
项目代码使用了DWR组件来进行异步调用,采用的DWR版本为3.0,但最近WebLogic经常发生线程STUCK,经过分析WebLogic的日志,发现了如下信息:
<2015-10-29 上午09时25分44秒 GMT+08:00> <Error> <WebLogicServer> <BEA-000337> <[STUCK] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)' has been busy for "652" seconds working on the request "Workmanager: default, Version: 0, Scheduled=true, Started=true, Started time: 652387 ms 
", which is more than the configured time (StuckThreadMaxTime) of "600" seconds in "server-failure-trigger". Stack trace: 
java.util.HashMap.put(HashMap.java:508) 
java.util.HashSet.add(HashSet.java:217) 
org.directwebremoting.impl.DefaultScriptSessionManager.associateScriptSessionAndPage(DefaultScriptSessionManager.java:242) 
org.directwebremoting.impl.DefaultScriptSessionManager.getScriptSession(DefaultScriptSessionManager.java:125) 
org.directwebremoting.impl.DefaultWebContext.checkPageInformation(DefaultWebContext.java:87) 
org.directwebremoting.dwrp.BaseCallHandler.handle(BaseCallHandler.java:97) 
org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:120) 
org.directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:141)

从堆栈上分析师
org.directwebremoting.impl.DefaultScriptSessionManager
出了问题,查看了这个类里面的所有Map都是
new ConcurrentHashMap();
类型的。到底是什么原因呢?
我们再来分析一下这个方法的源码
 protected void associateScriptSessionAndPage(DefaultScriptSession scriptSession, String page)
  {
    if (page == null)
    {
      return;
    }

    String normalizedPage = this.pageNormalizer.normalizePage(page);

    Set pageSessions = (Set)this.pageSessionMap.get(normalizedPage);
    if (pageSessions == null)
    {
      pageSessions = new HashSet();
      Set prev = (Set)this.pageSessionMap.putIfAbsent(normalizedPage, pageSessions);
      if (prev != null)
      {
        pageSessions = prev;
      }
    }

    pageSessions.add(scriptSession);
    scriptSession.setAttribute("org.directwebremoting.ScriptSession.Page", normalizedPage);
  }
我们发现pageSessions没有进行同步操作,所以我们的修改方案是:
synchronized (pageSessions) {
      pageSessions.add(scriptSession);
      scriptSession.setAttribute("comtop.org.directwebremoting.ScriptSession.Page", normalizedPage);
    }


    问题解决,当然有其他类似的地方还需要修改。


    现在来分析一下原因:java中常用的HashSet、ArrayList、HashMap都是线程不安全的,如果多条线程访问他们,而且多于一条的线程试图修改它们,则可能出错。我们遇到的情况就是属于多线程死锁。一般的解决方案有:
   1.使用ConcrrentHashMap替代HashMap
   2.对象的操作使用同步关键词synchronized
   3.得到线程安全的集合
  
Collection c = Collections.synchronizedCollection(new ArrayList());
        List l = Collections.synchronizedList(new ArrayList());
        Set s = Collections.synchronizedSet(new HashSet());
        Map m = Collections.synchronizedMap(new HashMap());