【问题标题】:Threads stuck at 100% CPU utilization in HashMap during JSF saveState()在 JSF saveState() 期间,线程卡在 HashMap 中的 100% CPU 利用率
【发布时间】:2015-12-29 00:02:59
【问题描述】:

我们的生产环境中存在问题,HTOP 命令的 4 线程的 CPU 使用率为 100%。为了进一步调查这个问题,我生成了一个线程转储,以便找出占用 CPU 的线程。

这是我发现的。 4 个线程具有相同的堆栈跟踪,所有这些都处于 RUNNABLE 状态。不幸的是,我被困在我的调查中,因为堆栈跟踪没有参考我的内部代码,它更多的是在 Richfaces 方面。我认为这是 JSF 呈现页面的部分。

堆栈跟踪。

"ajp-0.0.0.0-8009-47" daemon prio=10 tid=0x00007fb8040af000 nid=0x172c runnable [0x00007fb8b3bf8000]
   java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.hash(HashMap.java:351)
    at java.util.HashMap.putForCreate(HashMap.java:512)
    at java.util.HashMap.putAllForCreate(HashMap.java:534)
    at java.util.HashMap.<init>(HashMap.java:320)
    at org.ajax4jsf.component.UIDataAdaptorBase.createChildStateCopy(UIDataAdaptorBase.java:894)
    at org.ajax4jsf.component.UIDataAdaptorBase.saveState(UIDataAdaptorBase.java:1554)
    at org.richfaces.component.UIDataTable.saveState(UIDataTable.java:181)
    at org.richfaces.component.html.HtmlDataTable.saveState(HtmlDataTable.java:1361)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1103)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1119)
    at org.ajax4jsf.component.AjaxViewRoot.processSaveState(AjaxViewRoot.java:751)
    at org.ajax4jsf.application.AjaxStateManager.getComponentStateToSave(AjaxStateManager.java:179)
    at org.ajax4jsf.application.AjaxStateManager.buildViewState(AjaxStateManager.java:515)
    at org.ajax4jsf.application.AjaxStateManager$SeamStateManagerWrapper.saveView(AjaxStateManager.java:106)
    at org.jboss.seam.jsf.SeamStateManager.saveView(SeamStateManager.java:89)
    at org.ajax4jsf.application.AjaxStateManager.saveSerializedView(AjaxStateManager.java:470)
    at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:615)
    at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:100)
    at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:176)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:266)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.josso.servlet.agent.GenericServletSSOAgentFilter.doFilter(GenericServletSSOAgentFilter.java:558)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:73)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:73)
    at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:206)
    at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
    at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
    at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
    at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:436)
    at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:384)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:722)

另一件事是,我有什么方法可以利用堆栈跟踪,假设我想生成一个日志,以便我可以知道我的应用程序中的哪个页面正在生成这个堆栈跟踪?或者我可以使用相位监听器?

任何帮助将不胜感激。 谢谢。

我正在使用 Seam 2.2、Richfaces 3.3.3 final、JSF 1.2。

【问题讨论】:

  • 可能是并发问题——一个共享的 HashMap 在没有正确同步的情况下被多个线程读/写。
  • 谢谢你,我认为你是对的。有没有办法找出它被调用的页面?这样我就可以开始看那里了。
  • 通常由 Thread.setName() 完成,使用嵌入 URL、IP 等的字符串。但不知道如何在 seam 中完成。
  • 谢谢,也许我会找到办法。

标签: java multithreading jsf


【解决方案1】:

这个,

java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.hash(HashMap.java:351)
    at java.util.HashMap.putForCreate(HashMap.java:512)
    at java.util.HashMap.putAllForCreate(HashMap.java:534)
    at java.util.HashMap.<init>(HashMap.java:320)

还有这个,

java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.getEntry(HashMap.java:446)
    at java.util.HashMap.get(HashMap.java:405)

当一个线程调用get() 而另一个线程同时调用put() 时,java.util.HashMap 是已知的线程安全问题。线程将在计算哈希期间陷入无限循环。这个问题的技术解决方案是使用ConcurrentMap 实现。另见 a.o. this dzone article.

但是,在您的具体情况下,

    at java.util.HashMap.<init>(HashMap.java:320)
    at org.ajax4jsf.component.UIDataAdaptorBase.createChildStateCopy(UIDataAdaptorBase.java:894)
    at org.ajax4jsf.component.UIDataAdaptorBase.saveState(UIDataAdaptorBase.java:1554)
    at org.richfaces.component.UIDataTable.saveState(UIDataTable.java:181)
    at org.richfaces.component.html.HtmlDataTable.saveState(HtmlDataTable.java:1361)
    at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1103)

当您的&lt;rich:dataTable&gt; 组件的状态即将被保存时,此问题似乎会出现。这反过来表明该组件的同一个实例正被多个线程访问。这是不对的,UIComponent 类首先从未设计为线程安全的。这反过来表明所讨论的组件实例不是 JSF 规范所要求的请求范围。例如,当您使用 binding 将组件绑定到会话范围或什至可能是应用程序范围的 bean,或者更糟糕的是静态字段时,就会发生这种情况。

<x:someComponent ... binding="#{nonRequestScopedBean.someComponent}">

您应该在您的代码库中查找这样的组件并相应地修复它,方法是确保 bean 是请求范围内的,或者针对您认为使用 binding 的需求/问题使用不同的解决方案成为正确的解决方案。

另见:

【讨论】:

  • 非常感谢您的清晰解释,这对澄清事情很有帮助。我将寻找任何不属于请求范围的绑定组件。另一个问题,有没有一种方法可以跟踪这个堆栈跟踪来自哪个页面?它将帮助我缩小对生成此错误的数据表的搜索范围。顺便说一句,我们在页面中使用了很多 a4j:keepAlive 标签,我认为这可能是相关的。再次感谢。
  • 很遗憾,JSF 页面名称不包含在异常中。对所有 *.xhtml 文件中的字符序列 "&lt;rich:dataTable" 执行项目范围的搜索应该可以帮助您入门。
  • 谢谢。我搜索了带有绑定的“rich:dataTable”,但没有找到。但是我们有很多“rich:dataTable”值属性指向Seam Session Scope Components。据我所知,会话范围组件默认是同步的,所以我认为这些组件是线程安全的是安全的,或者我错了。
  • 也有可能某些 bean 正在执行 viewRoot.findComponent("formId:tableId"),然后将其分配为范围太广的 bean 的属性。关键不一定是binding,而是UIComponent 实例在多个线程之间共享。错误地使用binding 只是最常见的原因。
  • 谢谢,我也会调查一下。
【解决方案2】:

经过长时间的分析,我的问题得到了解决。

由于我们使用的是 jsf 2.1.7 版本,UI 重复使用 2.1.7 版本中的 hashmap 实现。因此,当我们使用嵌套的 ui 时,重复 cpu 很高。 我已经用 JSTL 替换了 UI 重复,现在应用程序正在运行。

您也可以使用其他方式,您需要更改 JSF 2.2.4 或更高版本。

【讨论】:

    猜你喜欢
    • 2016-04-08
    • 1970-01-01
    • 2021-03-28
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 2011-04-16
    相关资源
    最近更新 更多