java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java线程堆栈捕获

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

作者:codecraft

这篇文章主要为大家介绍了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线程堆栈捕获的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文