Java tip: How to list and find threads and thread groups

Topics: Java
Technologies: Java 6+

Java's threads are essential for building complex applications, but thread control is split across several classes in different packages added at different times in the JDK's history. This tip shows how to connect these classes together to find threads and thread groups, and get thread information.

Introduction

The principal threading classes are Thread and ThreadGroup in java.lang. Java 5 added the ThreadInfo and ThreadMXBean classes in java.lang.management to get state information and CPU usage for threads. Java 6 expanded these to get information on locks held by threads. Java 5 also added java.util.concurrent classes for managing thread pools and creating special types of locks.

There is a lot of functionality here, but there are some gaps. For example, though thread groups are organized as a tree of groups within groups, there is no method to get the tree's root ThreadGroup. Though threads have names and IDs, there are no methods to search for them by name or ID. Methods on ThreadInfo give you important state and locking information about a thread, but there is no method to get a ThreadInfo for a Thread, or to get the Thread described by a ThreadInfo. And so on.

These functionality gaps are not fatal, just mildly annoying. Below are utility methods to help list and find threads, thread groups, and thread info. These utility methods build upon each other. To distinguish methods in this article from those in the JDK, I'll highlight the article's methods.

A ThreadUtilities class including all of these methods is available for download. The source is released under the Lesser GPL, version 2.

Getting Thread Groups

Every Thread is in a named ThreadGroup. Thread groups are used to organize related threads and restrict thread access. Threads in a group can interrupt the group's threads and set the group's maximum priority. But, threads can't access any other groups.

Thread groups are arranged hierarchically in a tree with groups containing groups containing groups. The root group of the tree is the JDK's "system" group containing administrative threads, like those for object finalizing and signal dispatching. The "main" group under the "system" group contains the main application thread and threads it creates.

Unfortunately, there's no method to get the root thread group or to search the thread group tree for a named group. Getting a list of all thread groups is also a bit tricky.

Getting the root thread group

To get the root thread group, first get the current thread and its thread group. Then get its parent group, then its parent group, and on up until you find a group with a null parent. That's the root ThreadGroup.

ThreadGroup rootThreadGroup = null;
 
ThreadGroup getRootThreadGroup( ) {
    if ( rootThreadGroup != null )
        return rootThreadGroup;
    ThreadGroup tg = Thread.currentThread( ).getThreadGroup( );
    ThreadGroup ptg;
    while ( (ptg = tg.getParent( )) != null )
        tg = ptg;
    return tg;
}

Since the same root thread group is used for the life of the JVM, you can safely cache it for faster future use.

Getting a list of all thread groups

The enumerate( ) method on a ThreadGroup lists that group's child groups. Pass a true second argument and it will recursively traverse the group and children to fill a given array with ThreadGroup objects. Start at the root ThreadGroup and you'll get a list of all thread groups, except the root thread group. Since method only lists the descendants of the root, you'll have to add the root to this list yourself.

This sounds simple enough, but if the array you pass to enumerate( ) is too small, the method silently drops some groups. To allocate an array the right size, you could use the activeGroupCount( ) method on a ThreadGroup but it returns the number of groups in that group only, not in total. There's no method to get the total number of thread groups. Even if there were such a method, it could be wrong a moment later if other threads add or destroy thread groups.

Instead, you'll have to make a guess at the right array size then call enumerate( ). The method returns the number of groups it added to your array. If that number equals your array size, some groups might have been silently dropped. Increase the array size and try again.

ThreadGroup[] getAllThreadGroups( ) {
    final ThreadGroup root = getRootThreadGroup( );
    int nAlloc = root.activeGroupCount( );
    int n = 0;
    ThreadGroup[] groups;
    do {
        nAlloc *= 2;
        groups = new ThreadGroup[ nAlloc ];
        n = root.enumerate( groups, true );
    } while ( n == nAlloc );
 
    ThreadGroup[] allGroups = new ThreadGroup[n+1];
    allGroups[0] = root;
    System.arraycopy( groups, 0, allGroups, 1, n );
    return allGroups;
}

Getting a thread group by name

To find a named thread group, you'll have to search the thread group tree. You can search recursively starting at the root thread group, but it's easier to loop through the array returned by the getAllThreadGroups( ) method above. Note that thread groups may not have unique names. This search will stop on the first group that matches.

ThreadGroup getThreadGroup( final String name ) {
    if ( name == null )
        throw new NullPointerException( "Null name" );
    final ThreadGroup[] groups = getAllThreadGroups( );
    for ( ThreadGroup group : groups )
        if ( group.getName( ).equals( name ) )
            return group;
    return null;
}

Getting Threads

Every Thread has a name and a unique long integer ID. The JDK's own threads have names like "Finalizer" and "Reference Handler". When applications don't name their threads, threads are automatically named "Thread-0", "Thread-1", and so on.

There's no method to get a Thread based upon its ID or name. And getting a list of all Thread objects has the same difficulties as getting a list of all ThreadGroup objects did above.

Getting a list of all threads

Another enumerate( ) method on a ThreadGroup lists that group's threads. With a true second argument, it will recursively traverse the group to fill a given array with Thread objects. Start at the root ThreadGroup and you'll get a list of all threads in the JVM.

The problem here is the same as that for listing thread groups. If the array you pass to enumerate( ) is too small, some threads might be silently dropped from the returned array. So, you'll need to take a guess at the array size, call enumerate( ), check the returned value, and try again if the array filled up. To get a good starting guess, look to the java.lang.management package. The ManagementFactory class there returns a ThreadMXBean who's getThreadCount( ) method returns the total number of threads in the JVM. Of course, this can change a moment later, but it's a good first guess.

Thread[] getAllThreads( ) {
    final ThreadGroup root = getRootThreadGroup( );
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
    int nAlloc = thbean.getThreadCount( );
    int n = 0;
    Thread[] threads;
    do {
        nAlloc *= 2;
        threads = new Thread[ nAlloc ];
        n = root.enumerate( threads, true );
    } while ( n == nAlloc );
    return java.util.Arrays.copyOf( threads, n );
}

Getting a list of all threads in a thread group

Listing the threads in just one thread group requires most of the same steps used above to get all threads in the JVM. The group's enumerate( ) method fills your array with Thread objects, but you have to allocate the array at the right size or threads might be silently dropped. Call activeCount( ) on the group to get the number of threads in the group at that instant. Then use a larger size in case threads are added in the mean time.

Thread[] getGroupThreads( final ThreadGroup group ) {
    if ( group == null )
        throw new NullPointerException( "Null thread group" );
    int nAlloc = group.activeCount( );
    int n = 0;
    Thread[] threads;
    do {
        nAlloc *= 2;
        threads = new Thread[ nAlloc ];
        n = group.enumerate( threads );
    } while ( n == nAlloc );
    return java.util.Arrays.copyOf( threads, n );
}

Getting a list of all threads in high-to-low priority order

Every thread has a numeric priority. The higher the priority, the more CPU time the thread is given. To get a list of all threads in priority order, start with the getAllThreads( ) method shown earlier. Then sort the list on thread priority. Since threads can change their priority at any time, the result is only approximately in high-to-low order.

Thread[] getAllThreadsPrioritized( ) {
    final Thread[] allThreads = getAllThreads( );
    Array.sort( allThreads, new java.util.Comparator<Thread>( ) {
        public int compare( final Thread t1, final Thread t2 ) {
            return t2.getPriority( ) - t1.getPriority( );
        }
    } );
    return allThreads;
}

Getting a list of all daemon threads

Daemons are background threads doing tasks to support the application. When the last non-daemon thread dies, daemon threads are stopped automatically and the JVM exits. The isDaemon( ) method on Thread tells you if a thread is a daemon.

The ThreadMXBean class has a getDaemonThreadCount( ) method that returns the current number of daemon threads, but there's no method to get a list of them. Instead, you'll have to loop through a list of all threads to find the daemons.

Thread[] getAllDaemonThreads( ) {
    final Thread[] allThreads = getAllThreads( );
    final Thread[] daemons = new Thread[allThreads.length];
    int nDaemon = 0;
    for ( Thread thread : allThreads )
        if ( thread.isDaemon( ) )
            daemons[nDaemon++] = thread; 
    return java.util.Arrays.copyOf( daemons, nDaemon );
}

Getting a list of all threads in a specific state

The getState( ) method on Thread tells you if the thread is runnable or if it is blocked waiting on something. There are six states, defined by the Thread.State enum:

  • NEW. The thread has been created, but hasn't run yet.
  • TERMINATED. The thread has run to completion, but hasn't been deleted yet by the JVM.
  • RUNNABLE. The thread is running.
  • BLOCKED. The thread is blocked waiting on a lock (such as in a synchronized block or method).
  • WAITING. The thread is waiting until another thread calls notify( ).
  • TIMED_WAITING. The thread is either waiting or in a sleep( ).

During debugging it can be useful to monitor which threads are in which states. To get a list of threads in a specific state, get a list of all threads and extract the ones in the state you want.

Thread[] getAllThreads( final Thread.State state ) {
    final Thread[] allThreads = getAllThreads( );
    final Thread[] found = new Thread[allThreads.length];
    int nFound = 0;
    for ( Thread thread : allThreads )
        if ( thread.getState( ) == state )
            found[nFound++] = thread; 
    return java.util.Arrays.copyOf( found, nFound );
}

Getting a list of all thread IDs

The ThreadMXBean class already has a method to return an array of IDs for all threads.

long[] getAllThreadIds( ) {
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
    return thbean.getAllThreadIds( );
}

Getting a thread by ID

If you have a thread ID, you'll have to loop through a list of all threads to find the corresponding Thread object.

Thread getThread( final long id ) {
    final Thread[] threads = getAllThreads( );
    for ( Thread thread : threads )
        if ( thread.getId( ) == id )
            return thread;
    return null;
}

Getting a thread by name

To find a named thread, again you'll have to loop through a list of all threads. Since thread names are not guaranteed to be unique, this loop will stop on the first matching thread.

Thread getThread( final String name ) {
    if ( name == null )
        throw new NullPointerException( "Null name" );
    final Thread[] threads = getAllThreads( );
    for ( Thread thread : threads )
        if ( thread.getName( ).equals( name ) )
            return thread;
    return null;
}

Getting Thread Info

A Thread object can tell you the thread's ID, name, priority, and state. But the Thread object doesn't tell you if the thread owns any locks, and it won't help you find what a blocked thread is waiting for. For information like this, you need the thread's ThreadInfo object in the java.lang.management package.

There are two forms of the ThreadInfo object. The light-weight form has minimal information and is quick to get. The heavy-weight form has detailed information on locks and a current stack trace. This one is expensive to get but much more useful. Both forms are returned by methods on the ThreadMXBean class returned by the ManagementFactory in java.lang.management.

You'll need to keep track of which form of ThreadInfo you get. Once you've got one, they are indistinguishable. But if you ask the light-weight form for lock information, you'll get an empty response. Only the heavy-weight form will return lock information, if the thread has any locks.

However, there is no method on Thread to get its ThreadInfo, and no method on ThreadInfo to get its Thread.

Getting a list of all thread infos

This is a bit more work than it first seems. The ThreadMXBean object's getAllThreadIds( ) method returns an array of all thread IDs. Pass that to the bean's getThreadInfo( ) method to get the ThreadInfo objects for those IDs. However, between one call and the next, threads may have died. When this occurs, getThreadInfo( ) adds a null to the returned array for the corresponding dead thread ID. To get a clean array without these nulls, loop through the returned array and make a new clean array.

There are two important forms of the getThreadInfo( ) method on ThreadMXBean. The first form takes a thread ID array and returns light-weight ThreadInfo objects. The second form adds two boolean arguments to indicate if heavy-weight information on monitors and synchronizers should be included.

Before asking for heavy-weight information, ask the JVM if it supports returning this information. If it doesn't, getThreadInfo( ) will throw an exception.

ThreadInfo[] getAllThreadInfos( ) {
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
    final long[] ids = thbean.getAllThreadIds( );
 
    ThreadInfo[] infos;
    if ( !thbean.isObjectMonitorUsageSupported( ) ||
        !thbean.isSynchronizerUsageSupported( ) )
        infos = thbean.getThreadInfo( ids );
    else
        infos = thbean.getThreadInfo( ids, true, true );
 
    final ThreadInfo[] notNulls = new ThreadInfo[infos.length];
    int nNotNulls = 0;
    for ( ThreadInfo info : infos )
        if ( info != null )
            notNulls[nNotNulls++] = info;
    if ( nNotNulls == infos.length )
        return infos;
    return java.util.Arrays.copyOf( notNulls, nNotNulls );
}

Getting thread info by thread ID

Pass the thread ID to getThreadInfo( ) on the ThreadMXBean class to get the corresponding ThreadInfo. Ask for heavy-weight lock information if available.

ThreadInfo getThreadInfo( final long id ) {
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
 
    if ( !thbean.isObjectMonitorUsageSupported( ) ||
        !thbean.isSynchronizerUsageSupported( ) )
        return thbean.getThreadInfo( id );
 
    final ThreadInfo[] infos = thbean.getThreadInfo(
        new long[] { id }, true, true );
    if ( infos.length == 0 )
        return null;
    return infos[0];
}

Getting thread info by thread

Call getId( ) on a Thread object, then use the getThreadInfo( ) method above.

ThreadInfo getThreadInfo( final Thread thread ) {
    if ( thread == null )
        throw new NullPointerExceptino( "Null thread" );
    return getThreadInfo( thread.getId( ) );
}

Getting thread info by thread name

There are two approaches. Get a list of all ThreadInfo objects using getAllThreadInfos( ) above, then loop through the list to find the one you want. Or, get a list of all Thread objects using getAllThreads( ) above, loop through that to find the thread you want, then get a ThreadInfo for that thread. Both approaches work, but the second one is faster. The getAllThreadInfos( ) method is slow because it gets heavy-weight information for all ThreadInfo objects, even though you only need it for one.

ThreadInfo getThreadInfo( final String name ) {
    if ( name == null )
        throw new NullPointerException( "Null name" );
    final Thread[] threads = getAllThreads( );
    for ( Thread thread : threads )
        if ( thread.getName( ).equals( name ) )
            return getThreadInfo( thread.getId( ) );
    return null;
}

Getting a thread by thread info

If you have a ThreadInfo, call it's getThreadId( ) method, then use the earlier getThread( ) method to search for the Thread using the returned ID.

Thread getThread( final ThreadInfo info ) {
    if ( info == null )
        throw new NullPointerException( "Null thread info" );
    return getThread( info.getThreadId( ) );
}

Getting Monitor and Lock Info

When a Thread enters a synchronized method or block, it gains exclusive access to a resource. That resource is locked and this is recorded in a MonitorInfo object available through the thread's heavy-weight ThreadInfo.

However, there is no method to find out which Thread owns a lock on an object, or what Thread another Thread is blocked on.

Getting the thread that's locking an object

There are two ways to refer to an Object in Java. The first is with a standard object reference. The second is with a globally unique "identity hash code". This is not the same as the hash code returned by hashCode( ) on Object. Subclasses can override that method so that its value isn't globally unique. Instead, you can get an object's unique identity hash code by calling identityHashCode( ) on System.

The identity hash code is needed here. A heavy-weight ThreadInfo object's getLockedMonitors( ) method returns a list of MonitorInfo objects. Each of these refers to a locked object by its identity hash code. To find the thread holding a lock on an object, loop through all threads and get the ThreadInfo for each one. Since an object can only be locked by one thread at a time, stop on the first identity hash code match.

Thread getLockingThread( final Object object ) {
    if ( object == null )
        throw new NullPointerException( "Null object" );
    final long identity = System.identityHashCode( object );
 
    final Thread[] allThreads = getAllThreads( );
    ThreadInfo info = null;
    MonitorInfo[] monitors = null;
    for ( Thread thread : allThreads ) {
        info = getThreadInfo( thread.getId( ) );
        if ( info == null )
            continue;
        monitors = info.getLockedMonitors( );
        for ( MonitorInfo monitor : monitors )
            if ( identity == monitor.getIdentityHashCode( ) )
                return thread;
    }
    return null;
}

Getting the object that's blocking a thread

ThreadInfo can return a LockInfo object describing the object a thread is currently blocked by. Call the getIdentityHashCode( ) method on LockInfo to get the identity hash code of that object.

Now what you need is a method to convert an identity hash code to an object reference. But there is no such method. And it's unlikely one will ever be added due to serious security and stability issues. Consider that an identity hash code uniquely identifies an object, much like a memory address. A malicious application could explore memory by guessing at hash codes and converting them to object references. This would bypass the JVM's security checks and enable all sorts of mischief.

Without an identity hash code to object conversion method, it is not possible to find the Object blocking a Thread.

Getting the thread that owns the object that's blocking a thread

While you can't get the object that's blocking a thread, you can get the thread that owns that object. Call getLockOwnerId( ) on the blocked thread's ThreadInfo. Then look up that thread by its ID.

Thread getBlockingThread( final Thread thread ) {
    final ThreadInfo info = getThreadInfo( thread );
    if ( info == null )
        return null;
    final long id = info.getLockOwnerId( );
    if ( id == -1 )
        return null;
    return getThread( id );
}

Downloads

ThreadUtilities.zip
The zip file contains "ThreadUtilities.java" defining all of the above methods, with javadoc comments. The code is provided under the Lesser GPL, version 2.

Comments

thanks !!!

thanks !!!

Great job

Great and useful job.

Great info, but maybe a minor bug?

First of all, Thanks for the info and the provided sources. Very useful indeed.
However, when incorporating the method getGroupThreads() into my program, it immediately ran into an infinite loop.
The group I was using the method on was starting with zero Threads and the method does not seem to handle that situation very well.
A small correction would be to change the fourth line into:

int nAlloc = group.activeCount( ) + 1; // Added + 1 to prevent infinite loop when 0 is returned

Thanks!!!

Thanks!!!

Getting a list of all threads:

Very nice, thank you.

btw:
You mention some problems in "Getting a list of all threads" (the array filling up).
How about: Thread.getAllStackTraces().keySet()
which returns first a Map, and reduces that to a List.

Re: Getting a list of all threads

This may work, though I have not verified it. One problem is that it returns a full stack trace for every thread. This is a very expensive thing to do.

good keep it up

good keep it up

Excellent article and

Excellent article and collection of methods.

fantastic, thank you very

fantastic, thank you very much

Thanks

The idea helped a lot.. Thanks for a valuable article

Thanks

What a great page. Thanks for all of the useful tips and explanations, and thanks for sharing the code.

Thanks

Great page!

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

Nadeau software consulting
Nadeau software consulting