diff options
Diffstat (limited to 'libjava/classpath/java/lang/management/ThreadInfo.java')
-rw-r--r-- | libjava/classpath/java/lang/management/ThreadInfo.java | 895 |
1 files changed, 895 insertions, 0 deletions
diff --git a/libjava/classpath/java/lang/management/ThreadInfo.java b/libjava/classpath/java/lang/management/ThreadInfo.java new file mode 100644 index 000000000..a4ecc76f5 --- /dev/null +++ b/libjava/classpath/java/lang/management/ThreadInfo.java @@ -0,0 +1,895 @@ +/* ThreadInfo.java - Information on a thread + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +import java.util.Arrays; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + +/** + * <p> + * A class which maintains information about a particular + * thread. This information includes: + * </p> + * <ul> + * <li><strong>General Thread Information:</strong> + * <ul> + * <li>The identifier of the thread.</li> + * <li>The name of the thread.</li> + * </ul> + * </li> + * <li><strong>Execution Information:</strong> + * <ul> + * <li>The current state of the thread (e.g. blocked, runnable)</li> + * <li>The object upon which the thread is blocked, either because + * the thread is waiting to obtain the monitor of that object to enter + * one of its synchronized monitor, or because + * {@link java.lang.Object#wait()} has been called while the thread + * was within a method of that object.</li> + * <li>The thread identifier of the current thread holding an object's + * monitor, upon which the thread described here is blocked.</li> + * <li>The stack trace of the thread (if requested on creation + * of this object</li> + * <li>The current locks held on object monitors by the thread.</li> + * <li>The current locks held on ownable synchronizers by the thread.</li> + * </ul> + * <li><strong>Synchronization Statistics</strong> + * <ul> + * <li>The number of times the thread has been blocked waiting for + * an object's monitor or in a {@link java.lang.Object#wait()} call.</li> + * <li>The accumulated time the thread has been blocked waiting for + * an object's monitor on in a {@link java.lang.Object#wait()} call. + * The availability of these statistics depends on the virtual machine's + * support for thread contention monitoring (see + * {@link ThreadMXBean#isThreadContentionMonitoringSupported()}.</li> + * </ul> + * </li> + * </ul> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ +public class ThreadInfo +{ + + /** + * The id of the thread which this instance concerns. + */ + private long threadId; + + /** + * The name of the thread which this instance concerns. + */ + private String threadName; + + /** + * The state of the thread which this instance concerns. + */ + private Thread.State threadState; + + /** + * The number of times the thread has been blocked. + */ + private long blockedCount; + + /** + * The accumulated number of milliseconds the thread has + * been blocked (used only with thread contention monitoring + * support). + */ + private long blockedTime; + + /** + * The name of the monitor lock on which this thread + * is blocked (if any). + */ + private String lockName; + + /** + * The id of the thread which owns the monitor lock on + * which this thread is blocked, or <code>-1</code> + * if there is no owner. + */ + private long lockOwnerId; + + /** + * The name of the thread which owns the monitor lock on + * which this thread is blocked, or <code>null</code> + * if there is no owner. + */ + private String lockOwnerName; + + /** + * The number of times the thread has been in a waiting + * state. + */ + private long waitedCount; + + /** + * The accumulated number of milliseconds the thread has + * been waiting (used only with thread contention monitoring + * support). + */ + private long waitedTime; + + /** + * True if the thread is in a native method. + */ + private boolean isInNative; + + /** + * True if the thread is suspended. + */ + private boolean isSuspended; + + /** + * The stack trace of the thread. + */ + private StackTraceElement[] trace; + + /** + * The array of information on monitors locked by the thread. + */ + private MonitorInfo[] lockedMonitors; + + /** + * The array of information on ownable synchronizers locked + * by the thread. + */ + private LockInfo[] lockedSynchronizers; + + /** + * Cache a local reference to the thread management bean. + */ + private static ThreadMXBean bean = null; + + /** + * Cache the {@link javax.management.openmbean.CompositeType} + * for the {@link StackTraceElement}. + */ + private static CompositeType seType; + + /** + * Constructs a new {@link ThreadInfo} corresponding + * to the thread details specified. + * + * @param threadId the id of the thread on which this + * new instance will be based. + * @param threadName the name of the thread on which + * this new instance will be based. + * @param threadState the state of the thread on which + * this new instance will be based. + * @param blockedCount the number of times the thread + * has been blocked. + * @param blockedTime the accumulated number of milliseconds + * the specified thread has been blocked + * (only used with contention monitoring enabled) + * @param lockName the name of the monitor lock the thread is waiting for + * (only used if blocked) + * @param lockOwnerId the id of the thread which owns the monitor + * lock, or <code>-1</code> if it doesn't have an owner + * (only used if blocked) + * @param lockOwnerName the name of the thread which owns the monitor + * lock, or <code>null</code> if it doesn't have an + * owner (only used if blocked) + * @param waitedCount the number of times the thread has been in a + * waiting state. + * @param waitedTime the accumulated number of milliseconds the + * specified thread has been waiting + * (only used with contention monitoring enabled) + * @param isInNative true if the thread is in a native method. + * @param isSuspended true if the thread is suspended. + * @param trace the stack trace of the thread to a pre-determined + * depth (see VMThreadMXBeanImpl) + * @param lockedMonitors an array of {@link MonitorInfo} objects + * representing locks held on object monitors + * by the thread. + * @param lockedSynchronizers an array of {@link LockInfo} objects + * representing locks held on ownable + * synchronizers by the thread. + * + * @since 1.6 + */ + private ThreadInfo(long threadId, String threadName, Thread.State threadState, + long blockedCount, long blockedTime, String lockName, + long lockOwnerId, String lockOwnerName, long waitedCount, + long waitedTime, boolean isInNative, boolean isSuspended, + StackTraceElement[] trace, MonitorInfo[] lockedMonitors, + LockInfo[] lockedSynchronizers) + { + this.threadId = threadId; + this.threadName = threadName; + this.threadState = threadState; + this.blockedCount = blockedCount; + this.blockedTime = blockedTime; + this.lockName = lockName; + this.lockOwnerId = lockOwnerId; + this.lockOwnerName = lockOwnerName; + this.waitedCount = waitedCount; + this.waitedTime = waitedTime; + this.isInNative = isInNative; + this.isSuspended = isSuspended; + this.trace = trace; + this.lockedMonitors = lockedMonitors; + this.lockedSynchronizers = lockedSynchronizers; + } + + /** + * Checks for an attribute in a {@link CompositeData} structure + * with the correct type. + * + * @param ctype the composite data type to check. + * @param name the name of the attribute. + * @param type the type to check for. + * @throws IllegalArgumentException if the attribute is absent + * or of the wrong type. + */ + static void checkAttribute(CompositeType ctype, String name, + OpenType type) + throws IllegalArgumentException + { + OpenType foundType = ctype.getType(name); + if (foundType == null) + throw new IllegalArgumentException("Could not find a field named " + + name); + if (!(foundType.equals(type))) + throw new IllegalArgumentException("Field " + name + " is not of " + + "type " + type.getClassName()); + } + + /** + * Returns the {@link javax.management.openmbean.CompositeType} for + * a {@link StackTraceElement}. + * + * @return the type for the stack trace element. + */ + static CompositeType getStackTraceType() + { + if (seType == null) + try + { + seType = new CompositeType(StackTraceElement.class.getName(), + "An element of a stack trace", + new String[] { "className", "methodName", + "fileName", "lineNumber", + "nativeMethod" + }, + new String[] { "Name of the class", + "Name of the method", + "Name of the source code file", + "Line number", + "True if this is a native method" + }, + new OpenType[] { + SimpleType.STRING, SimpleType.STRING, + SimpleType.STRING, SimpleType.INTEGER, + SimpleType.BOOLEAN + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "stack trace element.", e); + } + return seType; + } + + /** + * <p> + * Returns a {@link ThreadInfo} instance using the values + * given in the supplied + * {@link javax.management.openmbean.CompositeData} object. + * The composite data instance should contain the following + * attributes with the specified types: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>threadId</td><td>java.lang.Long</td></tr> + * <tr><td>threadName</td><td>java.lang.String</td></tr> + * <tr><td>threadState</td><td>java.lang.String</td></tr> + * <tr><td>suspended</td><td>java.lang.Boolean</td></tr> + * <tr><td>inNative</td><td>java.lang.Boolean</td></tr> + * <tr><td>blockedCount</td><td>java.lang.Long</td></tr> + * <tr><td>blockedTime</td><td>java.lang.Long</td></tr> + * <tr><td>waitedCount</td><td>java.lang.Long</td></tr> + * <tr><td>waitedTime</td><td>java.lang.Long</td></tr> + * <tr><td>lockName</td><td>java.lang.String</td></tr> + * <tr><td>lockOwnerId</td><td>java.lang.Long</td></tr> + * <tr><td>lockOwnerName</td><td>java.lang.String</td></tr> + * <tr><td>stackTrace</td><td>javax.management.openmbean.CompositeData[] + * </td></tr> + * </table> + * <p> + * The stack trace is further described as: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>className</td><td>java.lang.String</td></tr> + * <tr><td>methodName</td><td>java.lang.String</td></tr> + * <tr><td>fileName</td><td>java.lang.String</td></tr> + * <tr><td>lineNumber</td><td>java.lang.Integer</td></tr> + * <tr><td>nativeMethod</td><td>java.lang.Boolean</td></tr> + * </table> + * + * @param data the composite data structure to take values from. + * @return a new instance containing the values from the + * composite data structure, or <code>null</code> + * if the data structure was also <code>null</code>. + * @throws IllegalArgumentException if the composite data structure + * does not match the structure + * outlined above. + */ + public static ThreadInfo from(CompositeData data) + { + if (data == null) + return null; + CompositeType type = data.getCompositeType(); + checkAttribute(type, "ThreadId", SimpleType.LONG); + checkAttribute(type, "ThreadName", SimpleType.STRING); + checkAttribute(type, "ThreadState", SimpleType.STRING); + checkAttribute(type, "Suspended", SimpleType.BOOLEAN); + checkAttribute(type, "InNative", SimpleType.BOOLEAN); + checkAttribute(type, "BlockedCount", SimpleType.LONG); + checkAttribute(type, "BlockedTime", SimpleType.LONG); + checkAttribute(type, "WaitedCount", SimpleType.LONG); + checkAttribute(type, "WaitedTime", SimpleType.LONG); + checkAttribute(type, "LockName", SimpleType.STRING); + checkAttribute(type, "LockOwnerId", SimpleType.LONG); + checkAttribute(type, "LockOwnerName", SimpleType.STRING); + try + { + checkAttribute(type, "StackTrace", + new ArrayType(1, getStackTraceType())); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the array for the stack trace element.", + e); + } + OpenType foundType = type.getType("LockedMonitors"); + if (foundType != null) + try + { + CompositeType mType = new CompositeType(MonitorInfo.class.getName(), + "Information on a object monitor lock", + new String[] { "ClassName", + "IdentityHashCode", + "LockedStackDepth", + "LockedStackFrame" + }, + new String[] { "Name of the class", + "Identity hash code " + + "of the class", + "Stack depth at time " + + "of lock", + "Stack frame at time " + + "of lock", + }, + new OpenType[] { + SimpleType.STRING, SimpleType.INTEGER, + SimpleType.INTEGER, getStackTraceType() + }); + if (!(foundType.equals(new ArrayType(1, mType)))) + throw new IllegalArgumentException("Field LockedMonitors is not of " + + "type " + mType.getClassName()); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "object monitor information array.", e); + } + foundType = type.getType("LockedSynchronizers"); + if (foundType != null) + try + { + CompositeType lType = new CompositeType(LockInfo.class.getName(), + "Information on a lock", + new String[] { "ClassName", + "IdentityHashCode" + }, + new String[] { "Name of the class", + "Identity hash code " + + "of the class" + }, + new OpenType[] { + SimpleType.STRING, SimpleType.INTEGER + }); + if (!(foundType.equals(new ArrayType(1, lType)))) + throw new IllegalArgumentException("Field LockedSynchronizers is not of " + + "type " + lType.getClassName()); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "ownable synchronizerinformation array.", e); + } + CompositeData[] dTraces = (CompositeData[]) data.get("StackTrace"); + StackTraceElement[] traces = new StackTraceElement[dTraces.length]; + for (int a = 0; a < dTraces.length; ++a) + /* FIXME: We can't use the boolean as there is no available + constructor. */ + traces[a] = + new StackTraceElement((String) dTraces[a].get("ClassName"), + (String) dTraces[a].get("MethodName"), + (String) dTraces[a].get("FileName"), + ((Integer) + dTraces[a].get("LineNumber")).intValue()); + MonitorInfo[] mInfo; + if (data.containsKey("LockedMonitors")) + { + CompositeData[] dmInfos = (CompositeData[]) data.get("LockedMonitors"); + mInfo = new MonitorInfo[dmInfos.length]; + for (int a = 0; a < dmInfos.length; ++a) + mInfo[a] = MonitorInfo.from(dmInfos[a]); + } + else + mInfo = new MonitorInfo[]{}; + LockInfo[] lInfo; + if (data.containsKey("LockedSynchronizers")) + { + CompositeData[] dlInfos = (CompositeData[]) data.get("LockedSynchronizers"); + lInfo = new LockInfo[dlInfos.length]; + for (int a = 0; a < dlInfos.length; ++a) + lInfo[a] = new LockInfo((String) dlInfos[a].get("ClassName"), + (Integer) dlInfos[a].get("IdentityHashCode")); + } + else + lInfo = new LockInfo[]{}; + return new ThreadInfo(((Long) data.get("ThreadId")).longValue(), + (String) data.get("ThreadName"), + Thread.State.valueOf((String) data.get("ThreadState")), + ((Long) data.get("BlockedCount")).longValue(), + ((Long) data.get("BlockedTime")).longValue(), + (String) data.get("LockName"), + ((Long) data.get("LockOwnerId")).longValue(), + (String) data.get("LockOwnerName"), + ((Long) data.get("WaitedCount")).longValue(), + ((Long) data.get("WaitedTime")).longValue(), + ((Boolean) data.get("InNative")).booleanValue(), + ((Boolean) data.get("Suspended")).booleanValue(), + traces, mInfo, lInfo); + } + + /** + * Returns the number of times this thread has been + * in the {@link java.lang.Thread.State#BLOCKED} state. + * A thread enters this state when it is waiting to + * obtain an object's monitor. This may occur either + * on entering a synchronized method for the first time, + * or on re-entering it following a call to + * {@link java.lang.Object#wait()}. + * + * @return the number of times this thread has been blocked. + */ + public long getBlockedCount() + { + return blockedCount; + } + + /** + * <p> + * Returns the accumulated number of milliseconds this + * thread has been in the + * {@link java.lang.Thread.State#BLOCKED} state + * since thread contention monitoring was last enabled. + * A thread enters this state when it is waiting to + * obtain an object's monitor. This may occur either + * on entering a synchronized method for the first time, + * or on re-entering it following a call to + * {@link java.lang.Object#wait()}. + * </p> + * <p> + * Use of this method requires virtual machine support + * for thread contention monitoring and for this support + * to be enabled. + * </p> + * + * @return the accumulated time (in milliseconds) that this + * thread has spent in the blocked state, since + * thread contention monitoring was enabled, or -1 + * if thread contention monitoring is disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @see ThreadMXBean#isThreadContentionMonitoringEnabled() + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ + public long getBlockedTime() + { + if (bean == null) + bean = ManagementFactory.getThreadMXBean(); + // Will throw UnsupportedOperationException for us + if (bean.isThreadContentionMonitoringEnabled()) + return blockedTime; + else + return -1; + } + + /** + * Returns an array of {@link MonitorInfo} objects representing + * information on the locks on object monitors held by the thread. + * If no locks are held, or such information was not requested + * on creating this {@link ThreadInfo} object, a zero-length + * array will be returned. + * + * @return information on object monitors locked by this thread. + */ + public MonitorInfo[] getLockedMonitors() + { + return lockedMonitors; + } + + /** + * Returns an array of {@link LockInfo} objects representing + * information on the locks on ownable synchronizers held by the thread. + * If no locks are held, or such information was not requested + * on creating this {@link ThreadInfo} object, a zero-length + * array will be returned. + * + * @return information on ownable synchronizers locked by this thread. + */ + public LockInfo[] getLockedSynchronizers() + { + return lockedSynchronizers; + } + + /** + * <p> + * Returns a {@link LockInfo} object representing the + * lock on which this thread is blocked. If the thread + * is not blocked, this method returns <code>null</code>. + * </p> + * <p> + * The thread may be blocked due to one of three reasons: + * </p> + * <ol> + * <li>The thread is in the <code>BLOCKED</code> state + * waiting to acquire an object monitor in order to enter + * a synchronized method or block.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call to + * {@link java.lang.Object#wait()}.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call + * to {@link java.util.concurrent.locks.LockSupport#park()}. + * The lock is the return value of + * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> + * </ol> + * + * @return a {@link LockInfo} object representing the lock on + * which the thread is blocked, or <code>null</code> if + * the thread isn't blocked. + * @since 1.6 + * @see #getLockName() + */ + public LockInfo getLockInfo() + { + String lockName = getLockName(); + int at = lockName.indexOf('@'); + return new LockInfo(lockName.substring(0, at), + Integer.decode(lockName.substring(at + 1))); + } + + /** + * <p> + * Returns a {@link java.lang.String} representation of + * the lock on which this thread is blocked. If + * the thread is not blocked, this method returns + * <code>null</code>. + * </p> + * <p> + * The returned {@link java.lang.String} is constructed + * using the class name and identity hashcode (usually + * the memory address of the object) of the lock. The + * two are separated by the '@' character, and the identity + * hashcode is represented in hexadecimal. Thus, for a + * lock, <code>l</code>, the returned value is + * the result of concatenating + * <code>l.getClass().getName()</code>, <code>"@"</code> + * and + * <code>Integer.toHexString(System.identityHashCode(l))</code>. + * The value is only unique to the extent that the identity + * hash code is also unique. The value is the same as would + * be returned by <code>getLockInfo().toString()</code> + * </p> + * + * @return a string representing the lock on which this + * thread is blocked, or <code>null</code> if + * the thread is not blocked. + */ + public String getLockName() + { + if (!isThreadBlocked()) + return null; + return lockName; + } + + /** + * Returns the identifier of the thread which owns the + * monitor lock this thread is waiting for. -1 is returned + * if either this thread is not blocked, or the lock is + * not held by any other thread. + * + * @return the thread identifier of thread holding the lock + * this thread is waiting for, or -1 if the thread + * is not blocked or the lock is not held by another + * thread. + */ + public long getLockOwnerId() + { + if (!isThreadBlocked()) + return -1; + return lockOwnerId; + } + + /** + * Returns the name of the thread which owns the + * monitor lock this thread is waiting for. <code>null</code> + * is returned if either this thread is not blocked, + * or the lock is not held by any other thread. + * + * @return the thread identifier of thread holding the lock + * this thread is waiting for, or <code>null</code> + * if the thread is not blocked or the lock is not + * held by another thread. + */ + public String getLockOwnerName() + { + if (!isThreadBlocked()) + return null; + return lockOwnerName; + } + + /** + * <p> + * Returns the stack trace of this thread to the depth + * specified on creation of this {@link ThreadInfo} + * object. If the depth is zero, an empty array will + * be returned. For non-zero arrays, the elements + * start with the most recent trace at position zero. + * The bottom of the stack represents the oldest method + * invocation which meets the depth requirements. + * </p> + * <p> + * Some virtual machines may not be able to return + * stack trace information for a thread. In these + * cases, an empty array will also be returned. + * </p> + * + * @return an array of {@link java.lang.StackTraceElement}s + * representing the trace of this thread. + */ + public StackTraceElement[] getStackTrace() + { + return trace; + } + + /** + * Returns the identifier of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's identifier. + */ + public long getThreadId() + { + return threadId; + } + + /** + * Returns the name of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's name. + */ + public String getThreadName() + { + return threadName; + } + + /** + * Returns the state of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's state. + */ + public Thread.State getThreadState() + { + return threadState; + } + + /** + * Returns the number of times this thread has been + * in the {@link java.lang.Thread.State#WAITING} + * or {@link java.lang.Thread.State#TIMED_WAITING} state. + * A thread enters one of these states when it is waiting + * due to a call to {@link java.lang.Object.wait()}, + * {@link java.lang.Object.join()} or + * {@link java.lang.concurrent.locks.LockSupport.park()}, + * either with an infinite or timed delay, respectively. + * + * @return the number of times this thread has been waiting. + */ + public long getWaitedCount() + { + return waitedCount; + } + + /** + * <p> + * Returns the accumulated number of milliseconds this + * thread has been in the + * {@link java.lang.Thread.State#WAITING} or + * {@link java.lang.Thread.State#TIMED_WAITING} state, + * since thread contention monitoring was last enabled. + * A thread enters one of these states when it is waiting + * due to a call to {@link java.lang.Object.wait()}, + * {@link java.lang.Object.join()} or + * {@link java.lang.concurrent.locks.LockSupport.park()}, + * either with an infinite or timed delay, respectively. + * </p> + * <p> + * Use of this method requires virtual machine support + * for thread contention monitoring and for this support + * to be enabled. + * </p> + * + * @return the accumulated time (in milliseconds) that this + * thread has spent in one of the waiting states, since + * thread contention monitoring was enabled, or -1 + * if thread contention monitoring is disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @see ThreadMXBean#isThreadContentionMonitoringEnabled() + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ + public long getWaitedTime() + { + if (bean == null) + bean = ManagementFactory.getThreadMXBean(); + // Will throw UnsupportedOperationException for us + if (bean.isThreadContentionMonitoringEnabled()) + return waitedTime; + else + return -1; + } + + /** + * Returns true if the thread is in a native method. This + * excludes native code which forms part of the virtual + * machine itself, or which results from Just-In-Time + * compilation. + * + * @return true if the thread is in a native method, false + * otherwise. + */ + public boolean isInNative() + { + return isInNative; + } + + /** + * Returns true if the thread has been suspended using + * {@link java.lang.Thread#suspend()}. + * + * @return true if the thread is suspended, false otherwise. + */ + public boolean isSuspended() + { + return isSuspended; + } + + /** + * Returns a {@link java.lang.String} representation of + * this {@link ThreadInfo} object. This takes the form + * <code>java.lang.management.ThreadInfo[id=tid, name=n, + * state=s, blockedCount=bc, waitedCount=wc, isInNative=iin, + * isSuspended=is]</code>, where <code>tid</code> is + * the thread identifier, <code>n</code> is the + * thread name, <code>s</code> is the thread state, + * <code>bc</code> is the blocked state count, + * <code>wc</code> is the waiting state count and + * <code>iin</code> and <code>is</code> are boolean + * flags to indicate the thread is in native code or + * suspended respectively. If the thread is blocked, + * <code>lock=l, lockOwner=lo</code> is also included, + * where <code>l</code> is the lock waited for, and + * <code>lo</code> is the thread which owns the lock + * (or null if there is no owner). + * + * @return the string specified above. + */ + public String toString() + { + return getClass().getName() + + "[id=" + threadId + + ", name=" + threadName + + ", state=" + threadState + + ", blockedCount=" + blockedCount + + ", waitedCount=" + waitedCount + + ", isInNative=" + isInNative + + ", isSuspended=" + isSuspended + + (isThreadBlocked() ? + ", lockOwnerId=" + lockOwnerId + + ", lockOwnerName=" + lockOwnerName : "") + + ", lockedMonitors=" + Arrays.toString(lockedMonitors) + + ", lockedSynchronizers=" + Arrays.toString(lockedSynchronizers) + + "]"; + } + + /** + * <p> + * Returns true if the thread is in a blocked state. + * The thread is regarded as blocked if: + * </p> + * <ol> + * <li>The thread is in the <code>BLOCKED</code> state + * waiting to acquire an object monitor in order to enter + * a synchronized method or block.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call to + * {@link java.lang.Object#wait()}.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call + * to {@link java.util.concurrent.locks.LockSupport#park()}. + * The lock is the return value of + * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> + * </ol> + * + * @return true if the thread is blocked. + */ + private boolean isThreadBlocked() + { + return (threadState == Thread.State.BLOCKED || + threadState == Thread.State.WAITING || + threadState == Thread.State.TIMED_WAITING); + } + +} |