zoukankan      html  css  js  c++  java
  • java线程阻塞问题排查方法

      我开发的worker,每隔几个月线上都会阻塞一次,一直都没查出问题。今天终于了了这个心结。把解决过程总结下和大家分享。

        首先用jstack命令打出这个进程的全部线程堆栈。拿到线程dump文件之后,搜索自己的worker名字。

    1. "DefaultQuartzScheduler_Worker-10" prio=10 tid=0x00007f55cd54d800 nid=0x3e2e waiting for monitor entry [0x00007f51ab8f7000]
    2. java.lang.Thread.State: BLOCKED (on object monitor)
    3. at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:86)
    4. - waiting to lock <0x0000000782359268> (a com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl)
    5. at com.jd.chat.worker.service.timer.AccountIncSyncTimer.run(AccountIncSyncTimer.java:114)
    6. at com.jd.chat.worker.service.timer.AbstractTimer.start(AbstractTimer.java:44)
    7. at com.jd.chat.worker.service.timer.AbstractTimer.doJob(AbstractTimer.java:49)
    8. at com.jd.chat.worker.web.context.StartAppListener$TimerJob.execute(StartAppListener.java:188)
    9. at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
    10. at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
    11. - locked <0x0000000783641c68> (a java.lang.Object)




        很快便找到了线程在哪一行被阻塞。但是就凭这么点信息,并不能查出问题的真正原因,这里推荐一个工具,叫tda.bat。同事给我的,网上应该有下载。把这个dump文件导入到tda中。找到阻塞的线程。阻塞的线程是红色的。


       之所以说这个软件好,是因为当你找到blocked的线程后,界面的下方,会打出阻塞的更详细的线程堆栈。截取这个堆栈的部分信息。

    1. at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)
    2. at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    3. at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    4. at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:80)
    5. at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteUpdate(MappedStatement.java:216)
    6. at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:94)
    7. at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:457)
    8. at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90)
    9. at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:380)
    10. at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:1)
    11. at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:200)
    12. at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:378)
    13. at com.jd.im.data.dataresource.ImSqlMapClientTemplate.retriedWithoutAnyInterventionUpdate(ImSqlMapClientTemplate.java:169)
    14. at com.jd.im.data.dataresource.ImSqlMapClientTemplate.update(ImSqlMapClientTemplate.java:137)
    15. at com.jd.chat.dao.impl.WriteDaoImpl.update(WriteDaoImpl.java:21)
    16. at com.jd.chat.zone.service.impl.GroupServiceImpl.updateRoute(GroupServiceImpl.java:766)
    17. at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:267)
    18. - 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”,然后再拿这个关键字搜索整个进程堆栈。

    1. "DefaultQuartzScheduler_Worker-1" prio=10 tid=0x00007f55cd2aa000 nid=0x3e25 runnable [0x00007f51b02c0000]
    2. java.lang.Thread.State: RUNNABLE
    3. at java.net.SocketInputStream.socketRead0(Native Method)
    4. at java.net.SocketInputStream.read(SocketInputStream.java:129)
    5. at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
    6. at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
    7. at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
    8. - locked <0x0000000791370d50> (a java.io.BufferedInputStream)
    9. at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:82)
    10. at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:92)
    11. at org.mariadb.jdbc.internal.common.packet.RawPacket.nextPacket(RawPacket.java:77)
    12. at org.mariadb.jdbc.internal.common.packet.SyncPacketFetcher.getRawPacket(SyncPacketFetcher.java:67)
    13. at org.mariadb.jdbc.internal.mysql.MySQLProtocol.getResult(MySQLProtocol.java:891)
    14. at org.mariadb.jdbc.internal.mysql.MySQLProtocol.executeQuery(MySQLProtocol.java:982)
    15. at org.mariadb.jdbc.MySQLStatement.execute(MySQLStatement.java:280)
    16. - locked <0x0000000791370678> (a org.mariadb.jdbc.internal.mysql.MySQLProtocol)
    17. at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)

     

                   贴出这个进程堆栈的一部分。这个进程堆栈其实也就是刚刚tda软件界面下方展示的导致线程阻塞的真正的堆栈!这个线程是runnable状态的,可惜mysql是锁死的。也就是说阻塞在了mysql里。

        感觉这是一个由张三的命案牵出李四的命案的故事。

  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/tiancai/p/9559151.html
Copyright © 2011-2022 走看看