【发布时间】:2014-08-09 21:52:29
【问题描述】:
我在运行 Tomcat 的生产服务器上运行了三个线程转储,间隔 10 秒。我发现相同的线程(相同的线程 ID)出现在所有三个线程转储中,并且正在做完全相同的事情 - 处理 JSP 页面。这是否意味着它被卡住了?或者可能是Tomcat线程池中的同一个线程一遍又一遍地被分配相同的任务。
这是一个中等大小的应用程序,有很多 servlet/JSP 页面、业务逻辑和一个数据库。此外,它相当繁忙(每秒大约 20 个请求)。 Tomcat 独立运行(不落后于 Apache)。
编辑 1(附加信息):主页通常需要不到 10 秒的时间来呈现,因此这不能是对主页的典型单个请求。
编辑 2:几个小时后我又进行了一次线程转储(但没有重新启动 Tomcat),这个特定的线程正在做其他事情。这是否最终意味着线程没有卡住?
这是该特定线程的线程转储部分(仅列出一个,因为其他两个完全相同):
"http-bio-8080-exec-220" daemon prio=10 tid=0x00007f5c801de800 nid=0x3151 runnable [0x00007f5c74d28000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:366)
at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:240)
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:119)
at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:192)
at org.apache.coyote.Response.doWrite(Response.java:517)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:408)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
at org.apache.catalina.connector.OutputBuffer.realWriteChars(OutputBuffer.java:487)
at org.apache.tomcat.util.buf.CharChunk.append(CharChunk.java:312)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:528)
at org.apache.catalina.connector.CoyoteWriter.write(CoyoteWriter.java:152)
at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:119)
at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:336)
at java.io.Writer.write(Writer.java:157)
at org.apache.jasper.runtime.JspWriterImpl.print(JspWriterImpl.java:473)
at org.apache.taglibs.standard.tag.common.core.UrlSupport.doEndTag(UrlSupport.java:127)
at org.apache.jsp.WEB_002dINF.jsp.site.home_jsp._jspx_meth_c_005furl_005f22(home_jsp.java:1172)
at org.apache.jsp.WEB_002dINF.jsp.site.home_jsp._jspx_meth_c_005fif_005f2(home_jsp.java:1141)
at org.apache.jsp.WEB_002dINF.jsp.site.home_jsp._jspx_meth_c_005fforEach_005f1(home_jsp.java:1102)
at org.apache.jsp.WEB_002dINF.jsp.site.home_jsp._jspService(home_jsp.java:308)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
at inspirasites.servlets.HomeServlet.doGet(HomeServlet.java:102)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at inspirasites.filters.CharEncodingFilter.doFilter(CharEncodingFilter.java:23)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at inspirasites.filters.SiteFilter.doFilter(SiteFilter.java:45)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
- locked <0x00000000e12fb330> (a org.apache.tomcat.util.net.SocketWrapper)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
【问题讨论】:
-
是的,它可能被卡住或者同一个线程执行同一个任务(Tomcat 尽可能地重用线程)。 HTTP BIO 是一种阻塞类型的连接器,因此大部分时间将花在读取或(在这种情况下)写入套接字上。写入套接字没有超时,如果接收器在处理接收到的字节时真的很慢(例如交换),线程可能会被卡住(直到连接关闭或丢失)。但是对于每秒 3 个和 20 个请求的样本,重复使用的线程执行相同任务的可能性不大。
-
@vanOekel 首先,您应该将此作为答案,因为它非常有用。另外,我有一个后续问题:假设线程被卡住,那么在重新启动 Tomcat 之前的所有线程转储仍然会显示它执行相同的任务,对吗?换句话说,Tomcat 永远不会杀死一个卡住的线程。如果是这样,我现在可以进行另一个线程转储,看看它是否仍然存在 :)
-
我不愿给出答案:有人可能以前见过这种行为并且知道发生了什么(“不太可能”并不是真正的答案)。 Tomcat 不会杀死这样的线程,但我希望在某个时间出现警告/错误日志(“连接重置”或类似的东西)。除了线程转储,您还可以查看打开的连接(“netstat”) - 您应该看到相同的“远程 IP:端口”出现(尽管这也不是决定性的 - 套接字连接通常在请求之间重用(“ HTTP 保持活动状态"))。