显示 JVM 中当前 运行 的所有线程组和线程

Displaying all thread groups and threads currently running in JVM

所以我的任务是显示 JVM 中当前 运行 的所有线程组和属于这些组的所有线程。

这应该输出,以便首先显示线程组,然后在下面显示该组中的所有线程。这是为所有线程组完成的。目前我的代码将只显示每个线程组,然后显示每个线程,但我不确定如何达到我描述的输出。

这是我当前的代码:

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

public  ThreadGroup[] getAllThreadGroups(){


    ThreadGroup root= getThreadRoot();
    int estimate = root.activeGroupCount();
    ThreadGroup [] threads = new ThreadGroup[estimate];
    while ( root.enumerate( threads, true ) == threads.length ) {
        threads = new ThreadGroup[ threads.length * 2 ];
    }


    ThreadGroup[] allGroups = new ThreadGroup[threads.length+1];
    allGroups[0] = root;
    System.arraycopy( threads, 0, allGroups, 1, estimate );
    return allGroups;

}
public Thread[] getAllThreads(){

     ThreadGroup root= getThreadRoot();
     int estimate = root.activeGroupCount();
     Thread [] allThreads = new Thread[estimate];
     while ( root.enumerate( allThreads, true ) == allThreads.length ) {
         allThreads = new Thread[ allThreads.length * 2 ];
     }


     return allThreads;

}

和主要方法:

public static void main(String[] args)   {

    CreateDummyGroups create = new CreateDummyGroups();
    Functionality func = new Functionality();
    ThreadGroup[] tg = func.getAllThreadGroups();
    Thread[] t = func.getAllThreads();
    for (int i=0; i<tg.length; i++) {
        if(tg[i] != null){
        System.out.println("Name: " + tg[i].getName());
        }
    }
    for (int i=0; i<t.length; i++) {
        if(t[i] != null){
        System.out.println("Name: " + t[i].getName() + ", id: " + t[i].getId() 
                + ", State: " + t[i].getState() + ", Is daemon? " + t[i].isDaemon());
        }
}
}

}

首先,对于获得所有线程组和线程的分层输出的最简单解决方案,您只需要您的 getThreadRoot() 方法:

Functionality func = new Functionality();
func.getThreadRoot().list();

但是,它甚至会打印层次化的组,而不是仅包含线程作为子级的组列表。为此,您必须 嵌套 您的循环,即

CreateDummyGroups create = new CreateDummyGroups();
Functionality func = new Functionality();
ThreadGroup[] tg = func.getAllThreadGroups();
Thread[] t = func.getAllThreads();
for(int i=0; i<tg.length; i++) {
    if(tg[i] != null) {
        System.out.println("Name: " + tg[i].getName());
        for(int j=0; j<t.length; j++) {
            if(t[j] != null && t[j].getThreadGroup() == tg[i]) {
            System.out.println("    Name: " + t[j].getName() + ", id: " + t[j].getId() 
                    + ", State: " + t[j].getState() + ", Is daemon? " + t[j].isDaemon());
            }
        }
    }
}

这在内部循环中使用引用比较,只显示当前组的线程。更有效的方法是首先只获取当前组的线程,即向 Functionality:

添加一个方法
public Thread[] getThreadsOf(ThreadGroup group) {
    int estimate = group.activeCount();
    Thread[] groupThreads = new Thread[estimate];
    while(group.enumerate( groupThreads, false ) == groupThreads.length) {
        groupThreads = new Thread[ groupThreads.length * 2 ];
    }
    return groupThreads;
}

并将来电者更改为

CreateDummyGroups create = new CreateDummyGroups();
Functionality func = new Functionality();
ThreadGroup[] tg = func.getAllThreadGroups();
for(int i=0; i<tg.length; i++) {
    if(tg[i] != null) {
        System.out.println("Name: " + tg[i].getName());
        Thread[] t = func.getThreadsOf(tg[i]);
        for(int j=0; j<t.length; j++) {
            if(t[j] != null) {
            System.out.println("    Name: " + t[j].getName() + ", id: " + t[j].getId() 
                    + ", State: " + t[j].getState() + ", Is daemon? " + t[j].isDaemon());
            }
        }
    }
}

顺便说一下,由于 Java 5,这可以很好地写成

CreateDummyGroups create = new CreateDummyGroups();
Functionality func = new Functionality();
for(ThreadGroup tg: func.getAllThreadGroups()) {
    if(tg != null) {
        System.out.println("Name: " + tg.getName());
        for(Thread t: func.getThreadsOf(tg)) {
            if(t != null) {
                System.out.println("    Name: " + t.getName() + ", id: " + t.getId() 
                    + ", State: " + t.getState() + ", Is daemon? " + t.isDaemon());
            }
        }
    }
}

但请注意,这些旧的 enumerate 方法是非常不鼓励的。它们不仅使用起来很复杂,而且由于线程和组在您处理它们时可能会发生变化,因此结果容易出错。处理在某个时间点制作的单个快照更简单、更可靠:

CreateDummyGroups create = new CreateDummyGroups();
Map<ThreadGroup, List<Thread>> map = new LinkedHashMap<>();
for(Thread thread: Thread.getAllStackTraces().keySet()) {
    List<Thread> list = map.get(thread.getThreadGroup());
    if(list == null) {
        list = new ArrayList<>();
        map.put(thread.getThreadGroup(), list);
    }
    list.add(thread);
}


for(Map.Entry<ThreadGroup,List<Thread>> groupEntry: map.entrySet()) {
    System.out.println("Name: " + groupEntry.getKey().getName());
    for(Thread thread: groupEntry.getValue()) {
        System.out.println("    Name: " + thread.getName() + ", id: " + thread.getId() 
            + ", State: " + thread.getState() + ", Is daemon? " + thread.isDaemon());
    }
}

使用 Java 8 个功能时,此逻辑变得更加简单:

CreateDummyGroups create = new CreateDummyGroups();
Map<ThreadGroup, List<Thread>> map = Thread.getAllStackTraces().keySet()
    .stream().collect(Collectors.groupingBy(Thread::getThreadGroup));


map.forEach((group,threadList) -> {
    System.out.println("Name: " + group.getName());
    threadList.forEach(thread -> 
        System.out.println("    Name: " + thread.getName() + ", id: " + thread.getId() 
            + ", State: " + thread.getState() + ", Is daemon? " + thread.isDaemon())
    );
});

另一种获取所有线程的方法是使用 ThreadMXBean:

ThreadMXBean thbean = ManagementFactory.getThreadMXBean();
final long[] ids = thbean.getAllThreadIds();

从那里您可以获得各种信息,另请参阅:

https://github.com/liguobing/ToolCode/blob/master/ThreadUtilities.java

但不幸的是 ThreadMXBean 不能直接在 Android 上使用。