【问题标题】:How to get stack trace of a thread如何获取线程的堆栈跟踪
【发布时间】:2010-09-17 10:53:59
【问题描述】:

我有一个多线程应用程序。有几条消息到达应用程序并在单独的线程中处理。为此,我使用 java.util.concurrent 包中的 ThreadPoolExecutor 和 FutureTask 类。

有时我的应用程序会出现一些死锁。当发生死锁时,我想中断阻塞线程并记录该线程的堆栈跟踪,以便稍后解决死锁。

有什么方法可以在 Java 中找到该线程之外的线程的堆栈跟踪?

【问题讨论】:

  • 您的意思是要检测死锁并恢复?从来没有这样做过,但是使用堆栈跟踪对我来说听起来不是正确的方法..
  • 我需要堆栈跟踪,以便我知道线程卡在哪里并可以修复问题,以便应用程序在重新启动后正常工作。但是我想中断阻塞线程,以便应用程序工作,直到我找到一些时间来解决问题并释放它。

标签: java multithreading deadlock stack-trace


【解决方案1】:

请参阅here 了解如何生成堆栈跟踪,包括如何以编程方式执行此操作。在控制台中,Ctrl+Break 会将堆栈跟踪转储到标准输出。另请参阅this SO question 了解更多详情。

【讨论】:

  • 在 UNIX 环境中,向 java 进程发送“QUIT”(kill -QUIT <pid>) 信号也会将堆栈跟踪输出到标准输出。
【解决方案2】:

您可以在应用程序中不时(或在终止进程之前)记录所有线程的堆栈跟踪。为此,请使用:

Map<Thread, StackTraceElement[]> m = Thread.getAllStackTraces();
for(Map.Entry<Thread,  StackTraceElement[]> e : m.entrySet()) {
    log(e.getKey().toString());
    for (StackTraceElement s : e.getValue()) {
        log("  " + s);
    }
}

在每晚运行自动化测试时,有时某些测试用例会陷入僵局。我添加了一个等待 30 分钟的“TimeBomb”守护线程,然后按上述方式记录所有堆栈跟踪。

【讨论】:

    【解决方案3】:

    在进入死锁区域之前,设置一个字段,如,

    thread = Thread.currentThread();
    

    在您的监控线程中,您可以随时执行thread.getStackTrace(); 以获取该线程的堆栈跟踪。

    【讨论】:

      【解决方案4】:

      您使用 JStack。这是一个很好的blog entry,详细说明了如何获取堆栈跟踪。

      【讨论】:

        【解决方案5】:

        我不确定您是否希望从同一个 JVM 内或外部获取堆栈跟踪,但如果您希望使用外部工具获取堆栈跟踪,以下将有所帮助:

        • The Java VisualVM 工具可用于连接到正在运行的 JVM,其中可以转储线程堆栈。对于大多数使用 Java 6 的人来说,这通常是首选方法。一旦启动 VisualVM,可以通过在 Application 选项卡中选择进程来获取进程的线程转储。现在可以使用“线程”选项卡来查看正在运行的进程中的线程,并且在同一选项卡中,您会找到“线程转储”按钮来提取所需的信息。
        • JDK 中的jstack 实用程序也可用于生成线程堆栈跟踪。

        【讨论】:

          【解决方案6】:

          当发生死锁时,我想中断阻塞线程...

          可以实现一个定期任务来检查死锁(死锁是 java 内在的或基于 Lock)并在场景中涉及的所有线程上调用 interrupt。但是,这并不能保证它会解决您的问题。它很可能会再次发生这种情况。详情请见Dr Heinz's article on a deadlock detector

          事实上,不能保证interrupt 甚至会像这样释放一个被阻塞的进程。它是一种更好的方法来避免死锁情况,例如,使用具有超时和重试策略的锁或“先试后买”方法。

          我想记录这个线程的堆栈跟踪...

          如果您想以编程方式执行此操作,请再次遵循 Heinz 博士的示例。如果没有,请在发现问题后生成线程转储。

          有什么方法可以在 Java 中找到该线程之外的线程的堆栈跟踪?

          是和不是。您可以从其他 VM 转储线程,但它们的堆栈跟踪可能不像您想象的那样有用,无法确定死锁的原因。如果检测到真正的死锁(由 您的 应用程序 VM 的线程转储上的 JVM 本身),您应该拥有调试原因所需的一切(或多或少)。

          【讨论】:

            猜你喜欢
            • 2010-09-22
            • 1970-01-01
            • 2010-10-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多