【问题标题】:Get a list of all threads currently running in Java获取当前在 Java 中运行的所有线程的列表
【发布时间】:2009-08-24 16:30:11
【问题描述】:

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

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

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

【问题讨论】:

    标签: java multithreading jvm


    【解决方案1】:

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

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

    性能:12 个线程(Azul JVM 16.0.1、Windows 10、Ryzen 5600X)为 0 毫秒。

    【讨论】:

    • 虽然比提出的其他替代方案更清洁,但它的缺点是会产生获取所有线程的堆栈跟踪的成本。如果您无论如何都将使用这些堆栈跟踪,那么这显然是优越的。如果没有,那么除了干净的代码之外,这可能会明显变慢。
    • @Eddie 这是常识的假设,还是你做过实验?你说“明显慢得多”;慢多少?这值得么?我质疑任何为了效率而使代码变得更糟的尝试。如果您有效率要求量化衡量效率的基础设施,那么我同意人们让代码变得更糟,因为他们似乎知道自己在做什么。根据 Donald Knuth 的说法,请参阅 the root of all evil
    • 我没有为这些特定的替代方案计时,但我已经使用其他 Java 方法来收集堆栈跟踪而不是线程列表。性能影响似乎在很大程度上取决于您使用的 JVM(例如 JRockit 与 Sun JVM)。在您的特定情况下值得衡量。它是否会影响您取决于您​​的 JVM 选择以及您拥有的线程数。我发现通过 ThreadMXBean.dumpAllThreads 获取大约 250 个线程的所有堆栈跟踪需要 150 - 200 毫秒,而仅获取线程列表(没有跟踪)是不可测量的(0 毫秒)。
    • 在我的系统(Oracle Java 1.7 VM)上,快速检查显示此方法比下面的替代方法慢约 70..80 倍。堆栈跟踪和反射属于最繁重的 Java 操作。
    • @thejoshwolfe:当然,可读性是一个重要因素,不应该进行微优化等。但是,我在编写一个小型应用程序性能监视器时进行了研究。对于这种工具,最小的性能印记对于获得可靠的数据至关重要,因此我选择了 stacktrace-less 方法。
    【解决方案2】:

    获取根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() 直到数组大到可以包含所有条目。

    【讨论】:

    • 我很震惊这种策略在互联网上如此流行。 My strategy 更简单(1 行代码),并且与避免竞争条件的额外好处一样工作。
    • @thejoshwolfe:实际上,我同意 - 我认为您的答案要好得多,如果它不会迟到一年,它可能一开始就会被接受。如果 OP 仍然经常光顾 SO,他显然会这样做,那么建议他不要接受我的回答,而是接受你的回答。
    • 请注意,对于rootGroup 以外的任何内容,您应该使用new Thread[rootGroup.activeCount()+1]activeCount() 可能为零,如果是,您将陷入无限循环。
    • @thejoshwolfe 我想这个解决方案要便宜得多。
    • +1 这个被低估的答案,因为它更适合用于监控目的恕我直言。它固有的竞争条件在监控中并不重要。然而,正如一些 quick'n'dirty 测试显示的那样,它比基于堆栈跟踪的解决方案快 70-80 倍。对于监控,小的性能印记是必不可少的,因为您希望尽可能小地保持对被监控系统的影响(海森堡再次罢工 :) 对于调试,您可能需要更可靠的信息,stacktrace 方法可能是基本的。顺便说一句,MxBean 解决方案甚至比使用堆栈跟踪还要慢。
    【解决方案3】:

    是的,看看getting a list of threads。该页面上有很多示例。

    这是以编程方式进行的。如果你至少想要一个 Linux 上的列表,你可以使用这个命令:

    kill -3 processid
    

    VM 会做一个线程转储到标准输出。

    【讨论】:

    • 杀死-3?至少在我的 linux 上,那是“终端退出”。杀死,不列出。
    • cletus 确实是正确的——kill -3 将线程转储到标准输出,无论信号应该是什么意思。我会考虑改用 jstack。
    • getting a list of threads 无法访问:nadeausoftware.com 拒绝连接。
    【解决方案4】:

    您可以从ThreadMXBean 获得很多关于线程的信息。

    调用静态ManagementFactory.getThreadMXBean() 方法获取对MBean 的引用。

    【讨论】:

      【解决方案5】:

      你看过jconsole吗?

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

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

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

      【讨论】:

      • 我想访问我的 java 类中的列表
      • 在这种情况下,请查看 cletus 的回答。
      • 嗯,当这家伙说他想要一个程序化解决方案时,为什么人们要投票呢?
      • 因为问题没有说明这一点。我将编辑问题以使其明确。
      【解决方案6】:

      你可以试试这样的:

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

      如果你需要,你显然可以获得更多的线程特性。

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          Groovy中你可以调用私有方法

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

          Java 中,只要安全管理器允许,您就可以使用反射调用该方法。

          【讨论】:

          • 我收到错误,getThreads 没有为 Thread 定义。而且我在文档中没有看到这个功能。
          【解决方案9】:

          代码 sn-p 获取主线程启动的线程列表:

          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
          

          【讨论】:

            【解决方案10】:

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

            jstack -l <PID>
            

            &lt;PID&gt; 是您计算机上运行的进程的 ID。要获取您的 java 进程的进程 ID,您只需运行 jps 命令即可。

            此外,您还可以在 TDA(线程转储分析器)中分析 jstack 生成的线程转储,例如 fastthreadspotify thread analyzer tool

            【讨论】:

              【解决方案11】:

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

              【讨论】:

                【解决方案12】:
                    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 + "  ");
                        }
                    }
                

                【讨论】:

                  【解决方案13】:

                  您可以使用返回所有活动线程 ID 的 getAllThreadIds。此方法返回时,返回的数组中包含的某些线程可能已终止。

                  ManagementFactory.getThreadMXBean().getAllThreadIds()
                  

                  【讨论】:

                  • 你应该在你的答案周围提供更多的背景信息,这不仅对提问者有用,而且对其他遇到问题的人也有用。
                  • 这给出了线程ID而不是线程类的实例,这就是这个问题所要问的。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多