获取当前正在Java中运行的所有线程的列表


232

有什么办法可以获取当前JVM中所有正在运行的线程的列表(包括不是由我的类启动)?

是否还可以获取列表中所有线程的ThreadClass对象?

我希望能够通过代码做到这一点。

Answers:


325

要获得一个可迭代的集合:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();

19
尽管比提出的其他替代方案要干净得多,但这样做的缺点是,需要为所有线程获取堆栈跟踪信息。如果仍然要使用那些堆栈跟踪,那么这显然是更好的。如果不是这样,那么除了干净的代码外,这可能会变得很慢,没有任何收益。
艾迪

29
@Eddie这是基于常识的假设,还是您做过实验?你说“明显慢”;慢多少?这值得么?我质疑为提高效率而使代码更糟的任何尝试。如果您有效率要求用于定量测量效率的基础架构,那么我认为人们会使代码变得更糟,因为他们似乎知道自己在做什么。参见所有罪恶的根源,根据高德纳。
thejoshwolfe 2011年

20
我没有为这些特定的替代方法计时,但是我使用了其他Java手段来收集堆栈跟踪,而不仅仅是收集线程列表。对性能的影响似乎在很大程度上取决于您所使用的JVM(例如,JRockit与Sun JVM)。在您的特定情况下值得衡量。它是否会影响您取决于您​​对JVM的选择以及所拥有的线程数。我发现通过ThreadMXBean.dumpAllThreads获取约250个线程的所有堆栈跟踪要花费150-200毫秒,而仅获取线程列表(无跟踪)是无法测量的(0毫秒)。
艾迪

4
在我的系统(Oracle Java 1.7 VM)上,快速检查显示此方法比以下方法慢70..80倍。堆栈跟踪和反射属于最重的Java操作。
Franz D.

5
@thejoshwolfe:当然,可读性是一个重要因素,不应对其进行微优化等。但是,我在编写小型应用程序性能监视器的同时进行了研究。对于这种工具,最低性能要求对于获取可靠数据至关重要,因此我选择了无堆栈跟踪方法。
Franz D.

75

获取根的句柄ThreadGroup,如下所示:

ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentGroup;
while ((parentGroup = rootGroup.getParent()) != null) {
    rootGroup = parentGroup;
}

现在,enumerate()重复在根组上调用该函数。第二个参数让您递归获取所有线程:

Thread[] threads = new Thread[rootGroup.activeCount()];
while (rootGroup.enumerate(threads, true ) == threads.length) {
    threads = new Thread[threads.length * 2];
}

注意我们如何重复调用enumerate()直到数组足够大以包含所有条目。


22
令我震惊的是,这种策略在互联网上如此流行。我的策略更简单(1行代码),并且在避免竞争情况方面也有很好的表现。
thejoshwolfe 2011年

11
@thejoshwolfe:实际上,我同意-我认为您的答案要好得多,如果不迟到一年,那么它可能首先会被接受。如果OP仍然很频繁地执行SO(显然是这样),则建议他不要接受我的回答,而应该接受您的回答。
Frerich Raabe 2012年

2
请注意,除了以外rootGroup,您都应该使用new Thread[rootGroup.activeCount()+1]activeCount()可能为零,如果为零,您将陷入无限循环。
jmiserez 2014年

7
@thejoshwolfe我想这个解决方案要便宜得多。
2014年

19
+1这个被低估的答案,因为它更适合监视IMHO。在监视中,其固有的竞赛条件并不重要。但是,正如一些快速测试所显示的那样,它比基于stacktrace的解决方案快70-80倍。对于监视,很小的性能影响是必不可少的,因为您希望将对监视系统的影响保持尽可能小(Heisenberg再次发出警告:)对于调试,在其中您可能需要更可靠的信息时,stacktrace方法可能是必要。顺便说一句,MxBean解决方案甚至比使用堆栈跟踪更慢。
Franz D.

29

是的,看看获取线程列表。该页面上有很多示例。

那是通过编程来完成的。如果您只想要Linux上的列表,则可以使用以下命令:

kill -3 processid

VM会将线程转储到stdout。


5
杀死-3?至少在我的Linux上,这是“终端退出”。杀死,不列出。
Michael H.

5
cletus确实是正确的-kill -3将线程转储到stdout,无论信号是什么意思。我会考虑使用jstack代替。
Dan Hardiker 2014年

无法获取线程列表:nadeausoftware.com拒绝连接。
DSlomer64


14

您看过jconsole吗?

这将列出为特定Java进程运行的所有线程。

您可以从JDK bin文件夹启动jconsole。

您也可以通过Ctrl+Break在Windows中单击或kill pid --QUIT在Linux中发送来获取所有线程的完整堆栈跟踪。


我想访问我的Java类中的列表
Kryten

在这种情况下,请看大叔的回答。
pjp

3
嗯,当那个家伙说他想要一个程序化的解决方案时,为什么人们对此表示支持?
cletus

因为问题没有说明。我将编辑问题以使其明确。
pjp

8

Apache Commons用户可以使用ThreadUtils。当前实现使用前面概述的遍历线程组方法。

for (Thread t : ThreadUtils.getAllThreads()) {
      System.out.println(t.getName() + ", " + t.isDaemon());
}

7

您可以尝试如下操作:

Thread.getAllStackTraces().keySet().forEach((t) -> System.out.println(t.getName() + "\nIs Daemon " + t.isDaemon() + "\nIs Alive " + t.isAlive()));

并且显然可以根据需要获得更多的线程特性。


5

Groovy中,您可以调用私有方法

// Get a snapshot of the list of all threads 
Thread[] threads = Thread.getThreads()

Java中,如果安全管理器允许,则可以使用反射调用该方法。


我收到错误消息,未为线程定义getThreads。而且我没有在文档中看到此功能。

4

代码片段获取由主线程启动的线程列表:

import java.util.Set;

public class ThreadSet {
    public static void main(String args[]) throws Exception{
        Thread.currentThread().setName("ThreadSet");
        for ( int i=0; i< 3; i++){
            Thread t = new Thread(new MyThread());
            t.setName("MyThread:"+i);
            t.start();
        }
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        for ( Thread t : threadSet){
            if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup()){
                System.out.println("Thread :"+t+":"+"state:"+t.getState());
            }
        }
    }
}

class MyThread implements Runnable{
    public void run(){
        try{
            Thread.sleep(5000);
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

输出:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE

如果需要程序尚未启动的所有线程(包括系统线程),请删除以下条件。

if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup())

现在输出:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[Reference Handler,10,system]:state:WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[Finalizer,8,system]:state:WAITING
Thread :Thread[Signal Dispatcher,9,system]:state:RUNNABLE
Thread :Thread[Attach Listener,5,system]:state:RUNNABLE

3
    public static void main(String[] args) {


        // Walk up all the way to the root thread group
        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
        ThreadGroup parent;
        while ((parent = rootGroup.getParent()) != null) {
            rootGroup = parent;
        }

        listThreads(rootGroup, "");
    }


    // List all threads and recursively list all subgroup
    public static void listThreads(ThreadGroup group, String indent) {
        System.out.println(indent + "Group[" + group.getName() + 
                ":" + group.getClass()+"]");
        int nt = group.activeCount();
        Thread[] threads = new Thread[nt*2 + 10]; //nt is not accurate
        nt = group.enumerate(threads, false);

        // List every thread in the group
        for (int i=0; i<nt; i++) {
            Thread t = threads[i];
            System.out.println(indent + "  Thread[" + t.getName() 
                    + ":" + t.getClass() + "]");
        }

        // Recursively list all subgroups
        int ng = group.activeGroupCount();
        ThreadGroup[] groups = new ThreadGroup[ng*2 + 10];
        ng = group.enumerate(groups, false);

        for (int i=0; i<ng; i++) {
            listThreads(groups[i], indent + "  ");
        }
    }

3

在Java控制台中,按Ctrl-Break。它将列出所有线程以及有关堆的一些信息。当然,这将使您无法访问对象。但是无论如何它对于调试还是很有帮助的。


1

要使用终端获取线程及其完整状态的列表,可以使用以下命令:

jstack -l <PID>

哪个PID是计算机上正在运行的进程的ID。要获取Java进程的进程ID,您只需运行jps命令即可。

另外,您可以分析jstack在TDA(线程转储分析器)中生成的线程转储,例如fastthreadspotify线程分析器工具


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.