java如何在应用代码里捕获线程堆栈
序
本文主要研究一下如何在应用代码里捕获线程堆栈
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) { boolean 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 getFormattedThreadDump(this.plainTextFormatter::format); } private <T> T getFormattedThreadDump(Function<ThreadInfo[], T> formatter) { return formatter.apply(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true)); }
springboot的ThreadDumpEndpoint则使用的是ManagementFactory.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线程堆栈捕获的资料请关注脚本之家其它相关文章!
相关文章
mybatis参数类型不匹配错误argument type mismatch的处理方案
这篇文章主要介绍了mybatis参数类型不匹配错误argument type mismatch的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-01-01详解Spring Boot 使用Spring security 集成CAS
本篇文章主要介绍了详解Spring Boot 使用Spring security 集成CAS,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2017-05-05SpringBoot使用Maven打包异常-引入外部jar的问题及解决方案
这篇文章主要介绍了SpringBoot使用Maven打包异常-引入外部jar,需要的朋友可以参考下2020-06-06
最新评论