开发者

java如何在应用代码里捕获线程堆栈

开发者 https://www.devze.com 2023-12-21 10:40 出处:网络 作者: codecraft
目录序getRunnableStackTracesreadRunnableStackTracesCommandProcessorThreadDumpEndpoint小结序 本文主要研究一下如何在应用代码里捕获线程堆栈
目录
  • getRunnableStackTraces
  • readRunnableStackTraces
    • CommandProcessor
  • ThreadDumpEndpoint
    • 小结

      本文主要研究一下如何在应用代码里捕获线程堆栈

      getRunnableStackTraces

      org/h2/util/Profiler.Java

      private static List<Object[]> getRunnableStackTraces() {
              ArrayList<Object[]> list = new ArrayList<>();
              Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
              for (Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
                  Thread t = entry.getKey();
                  if (t.getState() != Thread.State.RUNNABLE) {
                      continue;
                  }
                  StackTraceElement[] dump = entry.getValue();
                  if (dump == null || dump.length == 0) {
                      continue;
                  }
                  list.add(dump);
              }
              return list;
          }
      h2的Profiler的getRunnableStackTraces方法通过Thread.getAllStackTraces()来收集线程堆栈

      readRunnableStackTraces

      org/h2/util/Profiler.java

      private static List<Object[]> readRunnableStackTraces(int pid) {
              try {
                  String jstack = exec("jstack", Integer.toString(pid));
                  LineNumberReader r = new LineNumberReader(
                编程客栈          new StringReader(jstack));
                  return readStackTrace(r);
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
          }
      
          private static String exec(String... args) {
              ByteArrayOutputStream err = new ByteArrayOutputStream();
              ByteArrayOutputStream out = new ByteArrayOutputStream();
              try {
                  Process p = Runtime.getRuntime().exec(args);
                  copyInThread(p.getInputStream(), out);
                  copyInThread(p.getErrorStream(), err);
                  p.waitFor();
                  String e = new String(err.toByteArray(), StandardCharsets.UTF_8);
                  if (e.length() > 0) {
                      throw new RuntimeException(e);
                  }
                  return new String(out.toByteArray(), StandardCharsets.UTF_8);
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }
      h2的Profiler的readRunnableStackTraces方法则是基于给定的pid使用jstack来捕获线程堆栈

      CommandProcessor

      sun/jvm/hotspot/CommandProcessor.java

      new Command("jstack", "jstack [-v]", false) {
                  public void doit(Tokens t) {
                      bophpolean verbose = false;
                      if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
                          verbose = true;
                      }
                      StackTrace jstack = new StackTrace(verbose, true);
                      jstack.run(out);
                  }
              }
      sun.jvm.hotspot包的CommandProcessor提供了对jstack的支持

      ThreadDumpEndpoint

      org/springframework/boot/actuate/management/ThreadDumpEndpoint.java

      @ReadOperation(produces = "text/plain;charset=UTF-8")
          public String textThreadDump() {
              return getFormattedThr编程客栈eadDump(this.plainTextFormatter::format);
          }
      
          private <T> T getFormattedThreadDump(Function<ThreadInfo[], T> formatter) {
              return formatter.apply(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true));
          }
      springboot的ThreadDumpEnjavascriptdpoint则使用的是www.devze.comManagementFactory.getThreadMXBean().dumpAllThreads来获取线程堆栈

      小结

      在java运行时可以通过Thread.getAllStackTraces()、ManagementFactory.getThreadMXBean().dumpAllThreads来获取当前进程的线程堆栈信息,也可以通过Process调用jstack命令,值得注意的是jstack捕获的线程堆栈包含了nid

      (比如"C2 CompilerThread0" #7 daemon prio=9 os_prio=31 cpu=481.27ms elapsed=36.74s tid=0x00007fb08c068400 nid=0x6803 waiting on condition [0x0000000000000000])

      也就是top -H -p pid中展示的PID信息,而前面两个方法dump出来的没有nid这个信息。

      以上就是java如何在应用代码里捕获线程堆栈的详细内容,更多关于java线程堆栈捕获的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号