| /* 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); |
| } |
| |
| } |