【问题标题】:evaluation of a java thread dumpjava线程转储的评估
【发布时间】:2010-03-30 12:28:14
【问题描述】:

我得到了我的一个进程的线程转储。它有一堆这样的线程。我猜他们保留了一堆内存,所以我得到了 OOM。

"Thread-8264" prio=6 tid=0x4c94ac00 nid=0xf3c runnable [0x4fe7f000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c9bc640> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

"Thread-8241" prio=6 tid=0x4c94a400 nid=0xb8c runnable [0x4faef000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c36b808> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

我正试图找出它是如何出现这种情况的。 CustomThreadedExtractorWrapper 是一个包装类,它触发一个线程来完成一些工作(ExtractionThread,它使用 ZipExtractorCommonsCompress 从压缩流中提取 zip 内容)。如果任务耗时过长,则调用ExtractionThread.interrupt() 取消操作。

我可以在我的日志中看到取消发生了 25 次。我在我的转储中看到了其中的 21 个线程。我的问题:

  1. 这些线程的状态如何?活着还跑?以某种方式被阻止?
  2. 他们显然没有死于 .interrupt() 吗?有确定的方法可以真正杀死线程吗?
  3. 堆栈跟踪中“锁定”的真正含义是什么?

Inflater.java 中的第 223 行是:

public synchronized int inflate(byte[] b, int off, int len) {
    ...
    //return is line 223
    return inflateBytes(b, off, len);                          
}

【问题讨论】:

    标签: java thread-dump


    【解决方案1】:

    “锁定”表示他们拥有一台显示器;即方法为synchronized,线程转储显示执行同步的实例地址。

    您可以尝试使用Thread.stop() 杀死一个线程,但该线程可能会抵抗,而且它本质上是不安全的、已弃用且非常糟糕。不要做。此外,我不确定当线程处于本机方法时它是否有效,就像这里的情况一样。

    Thread.interrupt() 轻推目标线程。线程将在下一次显式查看中断标志或执行一些潜在的阻塞操作(I/O,或wait())时注意到它。线程可能会捕获异常并忽略它。

    您的线程是“可运行的”:它们没有被阻塞。 Inflater.inflate() 无论如何都不是阻塞函数;它只执行内存计算。本机实现中可能存在错误(Inflater.inflateBytes(),但这不太可能,因为这依赖于Zlib,这是一段非常稳定的代码)。更合理的是,其中一个调用者(例如您的 ZipExtractorCommonsCompress 类)陷入了一个循环,在该循环中它要求 Zip 提取器再处理零个字节,并且不明白它应该等待更多数据再重试。

    【讨论】:

      【解决方案2】:
      1. 所有这些线程都处于可运行状态

      2. interrupt 不会杀死线程...它只是一个指示线程是否被中断的标志,方法 sleep , wait 并且在线程中断时都会抛出 InteruptedException 。如果您想在中断时停止线程检查方法和 isInterupted() 并完成该线程中的所有工作

      3. locked 表示某个特定对象被该线程锁定

      【讨论】:

        【解决方案3】:

        如果可能,我建议您尝试使用 jvisualvm(它位于 JDK 安装的 bin 文件夹中)。它可以连接到任何本地 java 进程,并为您提供线程信息和内存信息(使用情况、分配的对象等)。该界面比控制台转储更容易解释。对于您的问题:

        Thread.State 的定义在 API 中:

        NEW - A thread that has not yet started is in this state.
        RUNNABLE - A thread executing in the Java virtual machine is in this state.
        BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
        WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
        TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
        TERMINATED - A thread that has exited is in this state.
        

        所以上面跟踪中的两个线程是活动的(注意可运行意味着它们可以运行,而不一定是它们正在运行,即操作系统调度程序可能会在另一个线程正在执行时暂停它们)。

        “杀死”线程的可能方法:

        • 有一个未捕获的异常
        • 调用线程的stop()
        • 让线程正常完成执行(即从 run() 退出)。

        对于您的第三个问题,我不确定,但我认为这是对线程持有的内部锁的引用。

        【讨论】:

        • 线程转储是用 jvisualvm 进行的...当我进行堆转储时,我的进程结束了
        【解决方案4】:

        有确定的方法可以真正杀死线程吗?

        不,没有。

        正如您所观察到的,Thread.interrupt() 建议线程停止,但它可能没有注意到,或者它可能决定不注意。

        唯一的其他选择是Thread.stop(),它已被弃用,因为它会严重破坏应用程序的稳定性。具体来说,Thread.stop() 导致所有线程锁被释放,但不保证锁所保护的状态处于可见状态。同时,意外异常意味着被stop() 中断的方法没有机会(例如)notify() 其他正在等待的线程。最后,线程有可能捕获(而不是重新抛出)ThreadDeath 异常对象,导致stop() 根本不停止线程。

        简而言之,致电Thread.stop() 是一个非常非常糟糕的主意。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-08-15
          • 2023-02-19
          • 2011-01-17
          • 2019-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多