java thread info
来源:互联网 发布:易顺佳服装软件 编辑:程序博客网 时间:2024/06/06 01:27
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.
Table of Contents
- Introduction
- Getting Thread Groups
- Getting the root thread group
- Getting a list of all thread groups
- Getting a thread group by name
- Getting Threads
- Getting a list of all threads
- Getting a list of all threads in a thread group
- Getting a list of all threads in high-to-low priority order
- Getting a list of all daemon threads
- Getting a list of all threads in a specific state
- Getting a list of all thread IDs
- Getting a thread by ID
- Getting a thread by name
- Getting Thread Info
- Getting a list of all thread infos
- Getting thread info by thread ID
- Getting thread info by thread
- Getting thread info by thread name
- Getting a thread by thread info
- Getting Monitor and Lock Info
- Getting the thread that's locking an object
- Getting the object that's blocking a thread
- Getting the thread that owns the object that's blocking a thread
- Downloads
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 withThreadGroup
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 theactiveGroupCount( )
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 thejava.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( ); Arrays.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. TheisDaemon( )
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 asynchronized
block or method).WAITING
. The thread is waiting until another thread callsnotify( )
.TIMED_WAITING
. The thread is either waiting or in asleep( )
.
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
injava.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 NullPointerException( "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. ThegetAllThreadInfos( )
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 );}
- java thread info
- system info & cpu core id & thread active
- JAVA Check Memory Info
- package-info.java
- package-info.java
- package-info.java文件
- package-info.java
- pacakge-info.java
- Java Info Instance Of
- java info polymorphism
- package-info.java
- Java Info basic 1
- Thread & Java
- Java Thread
- java Thread
- Java Thread
- Java Thread
- java thread
- js键盘监听事件
- test
- struts2+freemarker项目根路径设置源码分析
- Linux下挂载iso文件和配置yum本地源
- 新手上路,多多指教!
- java thread info
- android回调机制总结
- jdk maven 配置
- 我们在囧途之我要投诉你
- OpenCV的imread函数加载图像的完整路径问题
- 简谈--动态规划1
- 111111111111111111111
- 将myeclipse 控制台信息输出到文本文件
- 《高效学习OpenGL》之 通用的变换函数 glMatrixMode(),glLoadIdentity(),glLoadMatrixf(),glMultMatrixf();