【问题标题】:how to find out who create a thread in java?如何找出谁在java中创建了一个线程?
【发布时间】:2013-09-30 17:19:32
【问题描述】:

在tomcat中,如果一个webapp确实停止了一个none daemon线程,tomcat不能被shutdown.sh关闭

例如:

public class demo implements ServletContextListener{

  public void contextDestroyed(ServletContextEvent arg0) {
    // TODO Auto-generated method stub
    // yes,we can cancel timer in here,but this is not the major problem
   }

  public void contextInitialized(ServletContextEvent arg0) {        
    Timer timer = new Timer();
    timer.schedule(new Test(), 1000, 1000*10);
    }
}

public class Test extends TimerTask{  
@Override
public void run() {
    System.out.println("AAAA");        
   }
}

和上面一样,tomcat 不能被shutdown.sh 关闭。 来自 jvisualvm,线程检查员说:

"Timer-0" - Thread t@40
   java.lang.Thread.State: TIMED_WAITING
    at java.lang.Object.wait(Native Method)
    - waiting on <3957edeb> (a java.util.TaskQueue)
    at java.util.TimerThread.mainLoop(Timer.java:552)
    at java.util.TimerThread.run(Timer.java:505)

   Locked ownable synchronizers:
    - None

堆栈信息没有指出哪个java类创建了线程, 我的问题是如何从许多 webapps 中找出谁创建了线程。

谢谢!

【问题讨论】:

  • 最简单的方法是单独启动每个 webapp 并检查线程。
  • 谢谢,在测试环境下是个好方法,但是在线下怎么做呢?
  • 这个问题的更多讨论:stackoverflow.com/questions/11722749/…

标签: java multithreading tomcat


【解决方案1】:

以下是方法列表,从最快/最可靠到最慢/最难排序:

  1. 如果您有类的源代码,请在构造函数中创建一个异常(而不是实际抛出它)。当您需要知道线程何时创建时,您可以简单地检查或打印它。

  2. 如果您没有来源,线程名称可以很好地提示创建它的人。

  3. 如果名称暗示通用服务(如java.util.Timer),那么您可以在 IDE 的构造函数中创建条件断点。条件应该是线程名;当有人使用此名称创建线程时,调试器将停止。

  4. 如果你没有太多线程,在Thread的构造函数中设置断点。

  5. 如果您有很多线程,请将调试器附加到应用程序并冻结它。然后检查堆栈跟踪。

  6. 1234563请不要在生产环境中尝试此操作。
  7. 如果钱不是问题,您可以使用动态跟踪工具,例如 Compuware APM,或者,如果您使用的是 Linux 或 Solaris,则可以分别尝试 SystemTap 和 dtrace。

【讨论】:

  • 非常感谢@Aaron Digulla,非常好和详细。在这种情况下,我们只能像上面一样获取堆栈信息,所以我尝试使用 btrace 来获取更多详细信息,不幸的是我还没有得到任何有用的信息。无论如何,感谢 Aaron Digulla,您的回复包含很多有用的信息。
  • 谢谢@Aaron Digulla。您的第 4 点和第 5 点为我节省了一周的精力。将调试点附加到线程构造函数并进行调试以找出谁创建了导致我的应用程序出现问题的线程。
【解决方案2】:

如果您可以控制类,则可以在创建时捕获堆栈跟踪:

public class Test extends TimerTask {
  final StackTraceElement[] callerStack;

  public Test () {
    callerStack = Thread.currentThread().getStackTrace();
  }

  @Override
  public void run() {
    System.out.println("AAAA");
    System.out.println("Creator: "+Arrays.asList(callerStack));
  }

  @Override
  public String toString () {
    return "Test created by "+Arrays.asList(callerStack);
  }
}

【讨论】:

  • 对不起,在某些情况下,我们无法控制源代码,甚至没有导致tomcat关闭失败的线程或类。所以,我的问题是如何找出线程或类,以便我们可以通知代码所有者。
【解决方案3】:

您还可以编写一个小型 java Instrumentation 代理来包装线程构造函数(并在那里进行堆栈转储),而不是尝试修改 rt.jar 类。

【讨论】:

    【解决方案4】:

    如果您有 Eclipse 或 Intellij 之类的 IDE,则可以在各种 Thread 构造函数中设置断点。您可以使用调试器远程附加到进程。调试器将在构建线程时停止进程。您可以观察诸如线程名称之类的内容。如果要匹配特定线程名称,也可以使用带条件的断点。

    设置断点。 https://www.ibm.com/developerworks/library/os-ecbug/

    远程调试 https://dzone.com/articles/a-practical-guide-to-java-remote-debugging-in-the

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-17
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多