【问题标题】:How to find BOTH threads of a deadlock?如何找到死锁的两个线程?
【发布时间】:2011-04-11 20:59:07
【问题描述】:

我们正在 Tomcat 5.5 中运行经典的 spring/hibernate/mysql 堆栈。当尝试超时锁定表行时,有时我们会遇到死锁。引发某种死锁异常。

异常很清楚,堆栈跟踪表明出了什么问题。但它没有显示持有实际锁的另一个线程。除非我知道那根线在做什么,否则它只是大海捞针。

问题:有没有办法找到另一个线程?

谢谢!

一月

【问题讨论】:

  • 异常从何而来——mysql?你能发布一个堆栈跟踪吗?
  • 你怎么知道它只是另一个线程?死锁可能涉及一长串线程。
  • 我当然不知道涉及的线程数。但应用是典型的“一个请求=一个线程”的情况。我们对线程不做任何事情。而且由于锁是独占的,所以当时只能有一个线程。
  • org.springframework.dao.CannotAcquireLockException:无法插入集合:[com.customer.Site.siteLayoutSettingsRaw#48112];嵌套异常是 org.hibernate.exception.LockAcquisitionException: could not insert collection: [com.customer.Site.siteLayoutSettingsRaw#48112] at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:633) at org.springframework .orm.hibernate3.AbstractSessionFactoryBean.convertHibernateAccessException(AbstractSessionFactoryBean.java:303)
  • 引起:java.sql.BatchUpdateException:尝试获取锁时发现死锁;尝试在 com.mchange.v2.c3p0.impl.NewProxyPreparedStatement 的 com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1443) 的 com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1998) 重新启动事务。 executeBatch(NewProxyPreparedStatement.java:1723) 在 org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) 在 org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:56)

标签: java hibernate spring tomcat deadlock


【解决方案1】:

如果您需要查找持有锁的线程,您可以在 Eclipse 中通过调试视图执行此操作。查看http://archive.eclipse.org/eclipse/downloads/drops/R-3.1-200506271435/eclipse-news-part2b.html 并向下滚动到“调试锁和死锁”。

线程拥有的锁以及线程等待的锁都可以通过切换调试视图下拉菜单中的显示监视器菜单项在调试视图中内联显示。死锁中涉及的线程和锁以红色突出显示。

【讨论】:

    【解决方案2】:

    如果是代码问题,您可以尝试使用 jconsole 连接到正在运行的进程并检测死锁。

    【讨论】:

      【解决方案3】:

      不确定您是否已经弄清楚了,但如果它是一个死锁,线程转储在这里会有很大帮助。根据应用程序运行的操作系统以及您访问它的权限,您可以通过多种方式生成它。

      • 在 *nix 上向进程发送 QUIT 信号('kill -3 pid')将完成工作
      • 使用 jconsole/jvisualvm 可以选择获取它
      • 使用标准 jdk jstack(考虑 -F -l 选项)就可以解决问题
      • 如果您有幸使用 solaris pstack,将会有很大帮助

      一旦你得到它,分析锁定/等待线程以找到死锁。您可以手动执行此操作,也可以使用一些利用死锁检测算法的现有分析器。顺便说一句,jvm 有一个内置函数,它可以在线程转储中为您提供想法。

      如果我能提供更多帮助,请告诉我。

      祝你好运。

      问候, 呵呵

      【讨论】:

        【解决方案4】:

        下次遇到死锁时,请尝试在 MySQL 中使用以下命令。这应该会显示最后一个死锁。

        SHOW INNODB STATUS
        

        通常,当您在应用服务器上看到死锁时,日志只会显示受害线程(回滚的线程)。由于另一个线程已完成,因此不会引发异常。您需要返回数据库重新创建事务。

        一旦您从数据库中捕获了发生死锁的位置,您就可以进一步调查。

        【讨论】:

        • 这行不通,因为我无权访问数据库(当然它只是在生产中)。即使我可以,我也无法足够快地回溯到各种锁定对象背后的 Java 代码。我真的需要在抛出异常后立即找到JVM中的另一个线程。
        • 生产数据库的管理员应该能够为您收集所需的信息。知道哪两个 java 事务被锁定通常是没有用的。为此,您需要查看数据库上发生了什么。这将告诉您锁定发生在事务中的哪个位置,是否在索引、主键等中。访问此日志可以获得很多好处
        • 不应该是:SHOW ENGINE INNODB STATUS?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-10
        • 2018-06-16
        • 2016-04-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多