显示 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 上使用。
所以我的任务是显示 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 上使用。