java线程阻塞问题排查方法
来源:互联网 发布:云计算平台的特点包括 编辑:程序博客网 时间:2024/04/30 00:56
我开发的worker,每隔几个月线上都会阻塞一次,一直都没查出问题。今天终于了了这个心结。把解决过程总结下和大家分享。
首先用jstack命令打出这个进程的全部线程堆栈。拿到线程dump文件之后,搜索自己的worker名字。
"DefaultQuartzScheduler_Worker-10" prio=10 tid=0x00007f55cd54d800 nid=0x3e2e waiting for monitor entry [0x00007f51ab8f7000] java.lang.Thread.State: BLOCKED (on object monitor)at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:86)- waiting to lock <0x0000000782359268> (a com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl)at com.jd.chat.worker.service.timer.AccountIncSyncTimer.run(AccountIncSyncTimer.java:114)at com.jd.chat.worker.service.timer.AbstractTimer.start(AbstractTimer.java:44)at com.jd.chat.worker.service.timer.AbstractTimer.doJob(AbstractTimer.java:49)at com.jd.chat.worker.web.context.StartAppListener$TimerJob.execute(StartAppListener.java:188)at org.quartz.core.JobRunShell.run(JobRunShell.java:202)at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)- locked <0x0000000783641c68> (a java.lang.Object)
很快便找到了线程在哪一行被阻塞。但是就凭这么点信息,并不能查出问题的真正原因,这里推荐一个工具,叫tda.bat。同事给我的,网上应该有下载。把这个dump文件导入到tda中。找到阻塞的线程。阻塞的线程是红色的。
之所以说这个软件好,是因为当你找到blocked的线程后,界面的下方,会打出阻塞的更详细的线程堆栈。截取这个堆栈的部分信息。
at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:80)at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteUpdate(MappedStatement.java:216)at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:94)at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:457)at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90)at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:380)at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:1)at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:200)at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:378)at com.jd.im.data.dataresource.ImSqlMapClientTemplate.retriedWithoutAnyInterventionUpdate(ImSqlMapClientTemplate.java:169)at com.jd.im.data.dataresource.ImSqlMapClientTemplate.update(ImSqlMapClientTemplate.java:137)at com.jd.chat.dao.impl.WriteDaoImpl.update(WriteDaoImpl.java:21)at com.jd.chat.zone.service.impl.GroupServiceImpl.updateRoute(GroupServiceImpl.java:766)at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:267)- locked <0x0000000782359268> (a com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl)
这个才是真正有用的堆栈!它告诉了我程序是在执行SQL的时候,SQL发生死锁,于是线程被阻塞。它还提供了更有用的信息,那就是到底是哪个SQL导致的死锁。堆栈的倒数第三行指示了导致死锁的SQL。
但是一定要用这个工具才能找到具体的原因吗?答案当然是NO!
告诉大家怎么不通过工具找到阻塞的真正原因!
刚刚通过“BLOCKED”关键字搜到了线程堆栈,找到它的线程名“DefaultQuartzScheduler_Worker-10”。OK,然后,把最后的10改成1,也就是“DefaultQuartzScheduler_Worker-1”,然后再拿这个关键字搜索整个进程堆栈。
"DefaultQuartzScheduler_Worker-1" prio=10 tid=0x00007f55cd2aa000 nid=0x3e25 runnable [0x00007f51b02c0000] java.lang.Thread.State: RUNNABLEat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.read(SocketInputStream.java:129)at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)at java.io.BufferedInputStream.read(BufferedInputStream.java:317)- locked <0x0000000791370d50> (a java.io.BufferedInputStream)at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:82)at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:92)at org.mariadb.jdbc.internal.common.packet.RawPacket.nextPacket(RawPacket.java:77)at org.mariadb.jdbc.internal.common.packet.SyncPacketFetcher.getRawPacket(SyncPacketFetcher.java:67)at org.mariadb.jdbc.internal.mysql.MySQLProtocol.getResult(MySQLProtocol.java:891)at org.mariadb.jdbc.internal.mysql.MySQLProtocol.executeQuery(MySQLProtocol.java:982)at org.mariadb.jdbc.MySQLStatement.execute(MySQLStatement.java:280)- locked <0x0000000791370678> (a org.mariadb.jdbc.internal.mysql.MySQLProtocol)at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)
贴出这个进程堆栈的一部分。这个进程堆栈其实也就是刚刚tda软件界面下方展示的导致线程阻塞的真正的堆栈!这个线程是runnable状态的,可惜mysql是锁死的。也就是说阻塞在了mysql里。
感觉这是一个由张三的命案牵出李四的命案的故事。
1 0
- java线程阻塞问题排查方法
- Java模拟排查线程死锁问题
- java 线程阻塞的问题
- 常见的Java问题排查方法
- 常见的Java问题排查方法
- 常见的Java问题排查方法
- 常见的Java问题排查方法
- 常见的Java问题排查方法
- 常见的Java 问题排查方法
- Java中用interrupt()方法中断阻塞线程
- Java线程阻塞中断和LockSupport问题
- Java线程阻塞中断和LockSupport问题
- Java -- ExecutorService线程池触发的Full GC问题排查
- 虚拟机问题排查方法
- java 性能问题 排查
- java OOM问题排查
- Java问题排查工具箱
- Java问题排查利器
- Struts2 - 常用的constant总结
- Maven Tutorial - 快速安装、配置及使用
- 复制粘贴时导致eclipse(myeclipse、sts)卡死的解决办法
- C# 可空修饰符
- Android CircleProgressBar好看的圆形进度条
- java线程阻塞问题排查方法
- 并查集的详解与应用(基础篇)
- A006-AndroidManifest.xml解析
- 线段树模版(转)
- Android基础:广播接收器及其生命周期介绍
- POJ 3468 A Simple Problem with Integers (线段树,成段更新,区间求和)
- Mysql中limit的用法详解
- HDU3681Prison Break(BFS+TSP+二分+dp状态压缩)
- 关于jqGrid动态改变列的解决方案