ThreadDump分析小结

ThreadDump中包含了线程的状态信息,一般有 Runnable,BLOCKED,Wait几种状态。Wait一般都是线程池里面的线程,可以跳过,主要关注点应该放在Runnable和BLOCKED这两种状态。

我们可以根据当前服务器状态来看线程信息。

一.比如现在服务器cpu很低,内存占用也很低,但是卡,原因基本上有两个

1.线程阻塞了,下图看出来,报表在关闭的时候,需要等待原来报表计算完成(这个基本上是报表计算时间比较长,大部分可能是sql取数时间很长),这个线程一直在等,所以cpu占用率低。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"pool-56-thread-10" #669 prio=5 os_prio=0 tid=0x00007fa7f4005800 nid=0x3ab2c waiting for monitor entry [0x00007fa65545a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.fr.web.core.ReportSessionIDInfor.clearPageSet(Unknown Source)
- waiting to lock <0x00007fae6cd4cf10> (a com.fr.web.core.ReportSessionIDInfor)
at com.fr.web.core.TemplateSessionIDInfo.release(Unknown Source)
at com.fr.web.core.ReportSessionIDInfor.release(Unknown Source)
at com.fr.web.core.SessionPoolManager.processCloseSession(Unknown Source)
at com.fr.web.core.SessionPoolManager.access$200(Unknown Source)
at com.fr.web.core.SessionPoolManager$5.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

2.报表计算sql取数线程等待数据库返回数据,线程没事做,cpu利用率很低。这个线程状态是Runnable的,从socket缓存区读取数据。主要的特征就是依赖了外部api DruidPooledStatement.executeQuery,如果这种线程比较多,就是取数太慢了。

"pool-43-thread-1893" #4977 prio=5 os_prio=0 tid=0x00007f624950e000 nid=0x130b7 runnable [0x00007f6150bd3000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at com.sap.db.rte.comm.BasicSocketComm.receiveData(BasicSocketComm.java:494)
at com.sap.db.rte.comm.BasicSocketComm.receive(BasicSocketComm.java:582)
at com.sap.db.rte.comm.JdbcCommunication.execute(JdbcCommunication.java:116)
at com.sap.db.jdbc.ConnectionSapDB.execute(ConnectionSapDB.java:867)
at com.sap.db.jdbc.ConnectionSapDB.execute(ConnectionSapDB.java:820)
at com.sap.db.jdbc.StatementSapDB.sendCommand(StatementSapDB.java:898)
at com.sap.db.jdbc.StatementSapDB.sendSQL(StatementSapDB.java:947)
at com.sap.db.jdbc.StatementSapDB.execute(StatementSapDB.java:256)
at com.sap.db.jdbc.StatementSapDB.executeQuery(StatementSapDB.java:399)
at com.sap.db.jdbc.trace.Statement.executeQuery(Statement.java:184)
at com.fr.third.alibaba.druid.pool.DruidPooledStatement.executeQuery(DruidPooledStatement.java:140)
at com.fr.data.core.db.dialect.base.key.create.executequery.DialectExecuteQueryKey.execute(Unknown Source)
at com.fr.data.core.db.dialect.base.key.create.executequery.DialectExecuteQueryKey.execute(Unknown Source)
at com.fr.data.core.db.dialect.AbstractDialect.execute(Unknown Source)
at com.fr.data.core.db.dialect.DefaultDialect.executeQuery(Unknown Source)
at com.fr.data.impl.AbstractDBDataModel$1.call(Unknown Source)
at com.fr.data.impl.AbstractDBDataModel$1.call(Unknown Source)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

二.比如现在cpu很高,导致很卡,我们就需要关注一下,Runnable状态的线程。

如下图,一个线程在读取模板的时候,线程一直在runnable。那么这个Runnable和上面一个数据库Runnable有什么区别呢,主要区别就是这个是不涉及IO操作(数据库访问和redis访问都可以认为是IO操作,IO操作会导致cpu空闲)。

该线程一直在scanAttributeValue,cpu占满,卡顿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"Timer-7" #109 daemon prio=5 os_prio=0 tid=0x00007f8d7cba1000 nid=0x13b4 runnable [0x00007f8d400ef000]
java.lang.Thread.State: RUNNABLE
at com.fr.third.javax.xml.stream.XMLScanner.scanAttributeValue(XMLScanner.java:548)
at com.fr.third.javax.xml.stream.XMLNSDocumentScannerImpl.scanAttribute(XMLNSDocumentScannerImpl.java:499)
at com.fr.third.javax.xml.stream.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:298)
at com.fr.third.javax.xml.stream.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:1121)
at com.fr.third.javax.xml.stream.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:133)
at com.fr.third.javax.xml.stream.XMLReaderImpl.next(XMLReaderImpl.java:358)
at com.fr.third.javax.xml.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:56)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.data.impl.CustomDictionary.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.data.core.TableDataXmlUtils.readXMLDictionary(Unknown Source)
at com.fr.data.core.DataCoreXmlUtils.readXMLDictionary(Unknown Source)
at com.fr.base.present.DictPresent.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.xml.ReportXMLUtils.readPresent(Unknown Source)
at com.fr.report.cell.AbstractDynamicCellElement.readXML(Unknown Source)
at com.fr.report.cell.AbstractInsertCellElement.readXML(Unknown Source)
at com.fr.report.cell.AbstractExpandCellElement.readXML(Unknown Source)
at com.fr.report.cell.DefaultTemplateCellElement.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.report.elementcase.AbstractElementCase$1.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.report.elementcase.AbstractElementCase.readXML(Unknown Source)
at com.fr.report.report.AbstractECReport.readXML(Unknown Source)
at com.fr.report.worksheet.WorkSheet.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.main.AbstractFineBook.readReportXML(Unknown Source)
at com.fr.main.AbstractFineBook.readXML(Unknown Source)
at com.fr.main.AbstractTemplateWorkBook.readXML(Unknown Source)
at com.fr.stable.xml.XMLableReader.readXMLObject(Unknown Source)
at com.fr.main.impl.WorkBook.readStream(Unknown Source)
at com.fr.main.impl.WorkBook.readStream(Unknown Source)
at com.fr.io.TemplateWorkBookIO.readTemplateWorkBook(Unknown Source)
at com.fr.io.TemplateWorkBookIO.readTemplateWorkBook(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob.readTempalteId(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob.getAllFileTemplateId(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob.getAllFileTemplateId(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob.clearDatabaseData(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob.access$200(Unknown Source)
at com.fr.fs.web.service.favoriteparams.FavoriteParamsJob$2.run(Unknown Source)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)

三.有一些Runnable状态的线程可以忽略

1
2
3
4
5
6
7
8
9
10
11
12
"http-nio-10030-ClientPoller-0" #122 daemon prio=5 os_prio=0 tid=0x00007f8de038b800 nid=0x13c1 runnable [0x00007f8d3f8e9000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000829a3bb8> (a sun.nio.ch.Util$3)
- locked <0x00000000829a3ba8> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000829a38c8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:825)
at java.lang.Thread.run(Thread.java:748)

这个是nio的EpollWait,可以忽略