/* | 
|
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code 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 | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package java.lang.management;  | 
|
import javax.management.openmbean.CompositeData;  | 
|
import sun.management.ManagementFactoryHelper;  | 
|
import sun.management.ThreadInfoCompositeData;  | 
|
import static java.lang.Thread.State.*;  | 
|
/**  | 
|
* Thread information. <tt>ThreadInfo</tt> contains the information  | 
|
* about a thread including:  | 
|
* <h3>General thread information</h3>  | 
|
* <ul>  | 
|
* <li>Thread ID.</li>  | 
|
* <li>Name of the thread.</li>  | 
|
* </ul>  | 
|
*  | 
|
* <h3>Execution information</h3>  | 
|
* <ul>  | 
|
* <li>Thread state.</li>  | 
|
* <li>The object upon which the thread is blocked due to:  | 
|
* <ul>  | 
|
* <li>waiting to enter a synchronization block/method, or</li>  | 
|
 *       <li>waiting to be notified in a {@link Object#wait Object.wait} method, | 
|
* or</li>  | 
|
 *       <li>parking due to a {@link java.util.concurrent.locks.LockSupport#park | 
|
* LockSupport.park} call.</li>  | 
|
* </ul>  | 
|
* </li>  | 
|
* <li>The ID of the thread that owns the object  | 
|
* that the thread is blocked.</li>  | 
|
* <li>Stack trace of the thread.</li>  | 
|
* <li>List of object monitors locked by the thread.</li>  | 
|
* <li>List of <a href="LockInfo.html#OwnableSynchronizer">  | 
|
* ownable synchronizers</a> locked by the thread.</li>  | 
|
* </ul>  | 
|
*  | 
|
* <h4><a name="SyncStats">Synchronization Statistics</a></h4>  | 
|
* <ul>  | 
|
* <li>The number of times that the thread has blocked for  | 
|
* synchronization or waited for notification.</li>  | 
|
* <li>The accumulated elapsed time that the thread has blocked  | 
|
* for synchronization or waited for notification  | 
|
 *       since {@link ThreadMXBean#setThreadContentionMonitoringEnabled | 
|
* thread contention monitoring}  | 
|
* was enabled. Some Java virtual machine implementation  | 
|
* may not support this. The  | 
|
 *       {@link ThreadMXBean#isThreadContentionMonitoringSupported()} | 
|
* method can be used to determine if a Java virtual machine  | 
|
* supports this.</li>  | 
|
* </ul>  | 
|
*  | 
|
* <p>This thread information class is designed for use in monitoring of  | 
|
* the system, not for synchronization control.  | 
|
*  | 
|
* <h4>MXBean Mapping</h4>  | 
|
 * <tt>ThreadInfo</tt> is mapped to a {@link CompositeData CompositeData} | 
|
* with attributes as specified in  | 
|
 * the {@link #from from} method. | 
|
*  | 
|
* @see ThreadMXBean#getThreadInfo  | 
|
* @see ThreadMXBean#dumpAllThreads  | 
|
*  | 
|
* @author Mandy Chung  | 
|
* @since 1.5  | 
|
*/  | 
|
public class ThreadInfo { | 
|
private String threadName;  | 
|
private long threadId;  | 
|
private long blockedTime;  | 
|
private long blockedCount;  | 
|
private long waitedTime;  | 
|
private long waitedCount;  | 
|
private LockInfo lock;  | 
|
private String lockName;  | 
|
private long lockOwnerId;  | 
|
private String lockOwnerName;  | 
|
private boolean inNative;  | 
|
private boolean suspended;  | 
|
private Thread.State threadState;  | 
|
private StackTraceElement[] stackTrace;  | 
|
private MonitorInfo[] lockedMonitors;  | 
|
private LockInfo[] lockedSynchronizers;  | 
|
private static MonitorInfo[] EMPTY_MONITORS = new MonitorInfo[0];  | 
|
private static LockInfo[] EMPTY_SYNCS = new LockInfo[0];  | 
|
    /** | 
|
     * Constructor of ThreadInfo created by the JVM | 
|
     * | 
|
     * @param t             Thread | 
|
     * @param state         Thread state | 
|
     * @param lockObj       Object on which the thread is blocked | 
|
     * @param lockOwner     the thread holding the lock | 
|
     * @param blockedCount  Number of times blocked to enter a lock | 
|
     * @param blockedTime   Approx time blocked to enter a lock | 
|
     * @param waitedCount   Number of times waited on a lock | 
|
     * @param waitedTime    Approx time waited on a lock | 
|
     * @param stackTrace    Thread stack trace | 
|
*/  | 
|
private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,  | 
|
long blockedCount, long blockedTime,  | 
|
long waitedCount, long waitedTime,  | 
|
StackTraceElement[] stackTrace) {  | 
|
initialize(t, state, lockObj, lockOwner,  | 
|
blockedCount, blockedTime,  | 
|
waitedCount, waitedTime, stackTrace,  | 
|
EMPTY_MONITORS, EMPTY_SYNCS);  | 
|
}  | 
|
    /** | 
|
     * Constructor of ThreadInfo created by the JVM | 
|
     * for {@link ThreadMXBean#getThreadInfo(long[],boolean,boolean)} | 
|
     * and {@link ThreadMXBean#dumpAllThreads} | 
|
     * | 
|
     * @param t             Thread | 
|
     * @param state         Thread state | 
|
     * @param lockObj       Object on which the thread is blocked | 
|
     * @param lockOwner     the thread holding the lock | 
|
     * @param blockedCount  Number of times blocked to enter a lock | 
|
     * @param blockedTime   Approx time blocked to enter a lock | 
|
     * @param waitedCount   Number of times waited on a lock | 
|
     * @param waitedTime    Approx time waited on a lock | 
|
     * @param stackTrace    Thread stack trace | 
|
     * @param monitors      List of locked monitors | 
|
     * @param stackDepths   List of stack depths | 
|
     * @param synchronizers List of locked synchronizers | 
|
*/  | 
|
private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,  | 
|
long blockedCount, long blockedTime,  | 
|
long waitedCount, long waitedTime,  | 
|
StackTraceElement[] stackTrace,  | 
|
Object[] monitors,  | 
|
int[] stackDepths,  | 
|
Object[] synchronizers) {  | 
|
int numMonitors = (monitors == null ? 0 : monitors.length);  | 
|
MonitorInfo[] lockedMonitors;  | 
|
if (numMonitors == 0) {  | 
|
lockedMonitors = EMPTY_MONITORS;  | 
|
        } else { | 
|
lockedMonitors = new MonitorInfo[numMonitors];  | 
|
for (int i = 0; i < numMonitors; i++) {  | 
|
Object lock = monitors[i];  | 
|
String className = lock.getClass().getName();  | 
|
int identityHashCode = System.identityHashCode(lock);  | 
|
int depth = stackDepths[i];  | 
|
StackTraceElement ste = (depth >= 0 ? stackTrace[depth]  | 
|
: null);  | 
|
lockedMonitors[i] = new MonitorInfo(className,  | 
|
identityHashCode,  | 
|
depth,  | 
|
ste);  | 
|
}  | 
|
}  | 
|
int numSyncs = (synchronizers == null ? 0 : synchronizers.length);  | 
|
LockInfo[] lockedSynchronizers;  | 
|
if (numSyncs == 0) {  | 
|
lockedSynchronizers = EMPTY_SYNCS;  | 
|
        } else { | 
|
lockedSynchronizers = new LockInfo[numSyncs];  | 
|
for (int i = 0; i < numSyncs; i++) {  | 
|
Object lock = synchronizers[i];  | 
|
String className = lock.getClass().getName();  | 
|
int identityHashCode = System.identityHashCode(lock);  | 
|
lockedSynchronizers[i] = new LockInfo(className,  | 
|
identityHashCode);  | 
|
}  | 
|
}  | 
|
initialize(t, state, lockObj, lockOwner,  | 
|
blockedCount, blockedTime,  | 
|
waitedCount, waitedTime, stackTrace,  | 
|
lockedMonitors, lockedSynchronizers);  | 
|
}  | 
|
    /** | 
|
     * Initialize ThreadInfo object | 
|
     * | 
|
     * @param t             Thread | 
|
     * @param state         Thread state | 
|
     * @param lockObj       Object on which the thread is blocked | 
|
     * @param lockOwner     the thread holding the lock | 
|
     * @param blockedCount  Number of times blocked to enter a lock | 
|
     * @param blockedTime   Approx time blocked to enter a lock | 
|
     * @param waitedCount   Number of times waited on a lock | 
|
     * @param waitedTime    Approx time waited on a lock | 
|
     * @param stackTrace    Thread stack trace | 
|
     * @param lockedMonitors List of locked monitors | 
|
     * @param lockedSynchronizers List of locked synchronizers | 
|
*/  | 
|
private void initialize(Thread t, int state, Object lockObj, Thread lockOwner,  | 
|
long blockedCount, long blockedTime,  | 
|
long waitedCount, long waitedTime,  | 
|
StackTraceElement[] stackTrace,  | 
|
MonitorInfo[] lockedMonitors,  | 
|
LockInfo[] lockedSynchronizers) {  | 
|
this.threadId = t.getId();  | 
|
this.threadName = t.getName();  | 
|
this.threadState = ManagementFactoryHelper.toThreadState(state);  | 
|
this.suspended = ManagementFactoryHelper.isThreadSuspended(state);  | 
|
this.inNative = ManagementFactoryHelper.isThreadRunningNative(state);  | 
|
this.blockedCount = blockedCount;  | 
|
this.blockedTime = blockedTime;  | 
|
this.waitedCount = waitedCount;  | 
|
this.waitedTime = waitedTime;  | 
|
if (lockObj == null) {  | 
|
this.lock = null;  | 
|
this.lockName = null;  | 
|
        } else { | 
|
this.lock = new LockInfo(lockObj);  | 
|
this.lockName =  | 
|
lock.getClassName() + '@' +  | 
|
Integer.toHexString(lock.getIdentityHashCode());  | 
|
}  | 
|
if (lockOwner == null) {  | 
|
this.lockOwnerId = -1;  | 
|
this.lockOwnerName = null;  | 
|
        } else { | 
|
this.lockOwnerId = lockOwner.getId();  | 
|
this.lockOwnerName = lockOwner.getName();  | 
|
}  | 
|
if (stackTrace == null) {  | 
|
this.stackTrace = NO_STACK_TRACE;  | 
|
        } else { | 
|
this.stackTrace = stackTrace;  | 
|
}  | 
|
this.lockedMonitors = lockedMonitors;  | 
|
this.lockedSynchronizers = lockedSynchronizers;  | 
|
}  | 
|
    /* | 
|
     * Constructs a <tt>ThreadInfo</tt> object from a | 
|
     * {@link CompositeData CompositeData}. | 
|
*/  | 
|
private ThreadInfo(CompositeData cd) {  | 
|
ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd);  | 
|
threadId = ticd.threadId();  | 
|
threadName = ticd.threadName();  | 
|
blockedTime = ticd.blockedTime();  | 
|
blockedCount = ticd.blockedCount();  | 
|
waitedTime = ticd.waitedTime();  | 
|
waitedCount = ticd.waitedCount();  | 
|
lockName = ticd.lockName();  | 
|
lockOwnerId = ticd.lockOwnerId();  | 
|
lockOwnerName = ticd.lockOwnerName();  | 
|
threadState = ticd.threadState();  | 
|
suspended = ticd.suspended();  | 
|
inNative = ticd.inNative();  | 
|
stackTrace = ticd.stackTrace();  | 
|
        // 6.0 attributes | 
|
if (ticd.isCurrentVersion()) {  | 
|
lock = ticd.lockInfo();  | 
|
lockedMonitors = ticd.lockedMonitors();  | 
|
lockedSynchronizers = ticd.lockedSynchronizers();  | 
|
        } else { | 
|
// lockInfo is a new attribute added in 1.6 ThreadInfo  | 
|
// If cd is a 5.0 version, construct the LockInfo object  | 
|
            //  from the lockName value. | 
|
if (lockName != null) {  | 
|
String result[] = lockName.split("@");  | 
|
if (result.length == 2) {  | 
|
int identityHashCode = Integer.parseInt(result[1], 16);  | 
|
lock = new LockInfo(result[0], identityHashCode);  | 
|
                } else { | 
|
assert result.length == 2;  | 
|
lock = null;  | 
|
}  | 
|
            } else { | 
|
lock = null;  | 
|
}  | 
|
lockedMonitors = EMPTY_MONITORS;  | 
|
lockedSynchronizers = EMPTY_SYNCS;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns the ID of the thread associated with this <tt>ThreadInfo</tt>. | 
|
     * | 
|
     * @return the ID of the associated thread. | 
|
*/  | 
|
    public long getThreadId() { | 
|
return threadId;  | 
|
}  | 
|
    /** | 
|
     * Returns the name of the thread associated with this <tt>ThreadInfo</tt>. | 
|
     * | 
|
     * @return the name of the associated thread. | 
|
*/  | 
|
public String getThreadName() {  | 
|
return threadName;  | 
|
}  | 
|
    /** | 
|
     * Returns the state of the thread associated with this <tt>ThreadInfo</tt>. | 
|
     * | 
|
     * @return <tt>Thread.State</tt> of the associated thread. | 
|
*/  | 
|
public Thread.State getThreadState() {  | 
|
return threadState;  | 
|
}  | 
|
    /** | 
|
     * Returns the approximate accumulated elapsed time (in milliseconds) | 
|
     * that the thread associated with this <tt>ThreadInfo</tt> | 
|
     * has blocked to enter or reenter a monitor | 
|
     * since thread contention monitoring is enabled. | 
|
     * I.e. the total accumulated time the thread has been in the | 
|
     * {@link java.lang.Thread.State#BLOCKED BLOCKED} state since thread | 
|
     * contention monitoring was last enabled. | 
|
     * This method returns <tt>-1</tt> if thread contention monitoring | 
|
     * is disabled. | 
|
     * | 
|
     * <p>The Java virtual machine may measure the time with a high | 
|
     * resolution timer.  This statistic is reset when | 
|
     * the thread contention monitoring is reenabled. | 
|
     * | 
|
     * @return the approximate accumulated elapsed time in milliseconds | 
|
     * that a thread entered the <tt>BLOCKED</tt> state; | 
|
     * <tt>-1</tt> if thread contention monitoring is disabled. | 
|
     * | 
|
     * @throws java.lang.UnsupportedOperationException if the Java | 
|
     * virtual machine does not support this operation. | 
|
     * | 
|
     * @see ThreadMXBean#isThreadContentionMonitoringSupported | 
|
     * @see ThreadMXBean#setThreadContentionMonitoringEnabled | 
|
*/  | 
|
    public long getBlockedTime() { | 
|
return blockedTime;  | 
|
}  | 
|
    /** | 
|
     * Returns the total number of times that | 
|
     * the thread associated with this <tt>ThreadInfo</tt> | 
|
     * blocked to enter or reenter a monitor. | 
|
     * I.e. the number of times a thread has been in the | 
|
     * {@link java.lang.Thread.State#BLOCKED BLOCKED} state. | 
|
     * | 
|
     * @return the total number of times that the thread | 
|
     * entered the <tt>BLOCKED</tt> state. | 
|
*/  | 
|
    public long getBlockedCount() { | 
|
return blockedCount;  | 
|
}  | 
|
    /** | 
|
     * Returns the approximate accumulated elapsed time (in milliseconds) | 
|
     * that the thread associated with this <tt>ThreadInfo</tt> | 
|
     * has waited for notification | 
|
     * since thread contention monitoring is enabled. | 
|
     * I.e. the total accumulated time the thread has been in the | 
|
     * {@link java.lang.Thread.State#WAITING WAITING} | 
|
     * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state | 
|
     * since thread contention monitoring is enabled. | 
|
     * This method returns <tt>-1</tt> if thread contention monitoring | 
|
     * is disabled. | 
|
     * | 
|
     * <p>The Java virtual machine may measure the time with a high | 
|
     * resolution timer.  This statistic is reset when | 
|
     * the thread contention monitoring is reenabled. | 
|
     * | 
|
     * @return the approximate accumulated elapsed time in milliseconds | 
|
     * that a thread has been in the <tt>WAITING</tt> or | 
|
     * <tt>TIMED_WAITING</tt> state; | 
|
     * <tt>-1</tt> if thread contention monitoring is disabled. | 
|
     * | 
|
     * @throws java.lang.UnsupportedOperationException if the Java | 
|
     * virtual machine does not support this operation. | 
|
     * | 
|
     * @see ThreadMXBean#isThreadContentionMonitoringSupported | 
|
     * @see ThreadMXBean#setThreadContentionMonitoringEnabled | 
|
*/  | 
|
    public long getWaitedTime() { | 
|
return waitedTime;  | 
|
}  | 
|
    /** | 
|
     * Returns the total number of times that | 
|
     * the thread associated with this <tt>ThreadInfo</tt> | 
|
     * waited for notification. | 
|
     * I.e. the number of times that a thread has been | 
|
     * in the {@link java.lang.Thread.State#WAITING WAITING} | 
|
     * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state. | 
|
     * | 
|
     * @return the total number of times that the thread | 
|
     * was in the <tt>WAITING</tt> or <tt>TIMED_WAITING</tt> state. | 
|
*/  | 
|
    public long getWaitedCount() { | 
|
return waitedCount;  | 
|
}  | 
|
    /** | 
|
     * Returns the <tt>LockInfo</tt> of an object for which | 
|
     * the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is blocked waiting. | 
|
     * A thread can be blocked waiting for one of the following: | 
|
     * <ul> | 
|
     * <li>an object monitor to be acquired for entering or reentering | 
|
     *     a synchronization block/method. | 
|
     *     <br>The thread is in the {@link java.lang.Thread.State#BLOCKED BLOCKED} | 
|
     *     state waiting to enter the <tt>synchronized</tt> statement | 
|
     *     or method. | 
|
     *     <p></li> | 
|
     * <li>an object monitor to be notified by another thread. | 
|
     *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING} | 
|
     *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state | 
|
     *     due to a call to the {@link Object#wait Object.wait} method. | 
|
     *     <p></li> | 
|
     * <li>a synchronization object responsible for the thread parking. | 
|
     *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING} | 
|
     *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state | 
|
     *     due to a call to the | 
|
     *     {@link java.util.concurrent.locks.LockSupport#park(Object) | 
|
     *     LockSupport.park} method.  The synchronization object | 
|
     *     is the object returned from | 
|
     *     {@link java.util.concurrent.locks.LockSupport#getBlocker | 
|
     *     LockSupport.getBlocker} method. Typically it is an | 
|
     *     <a href="LockInfo.html#OwnableSynchronizer"> ownable synchronizer</a> | 
|
     *     or a {@link java.util.concurrent.locks.Condition Condition}.</li> | 
|
     * </ul> | 
|
     * | 
|
     * <p>This method returns <tt>null</tt> if the thread is not in any of | 
|
     * the above conditions. | 
|
     * | 
|
     * @return <tt>LockInfo</tt> of an object for which the thread | 
|
     *         is blocked waiting if any; <tt>null</tt> otherwise. | 
|
     * @since 1.6 | 
|
*/  | 
|
public LockInfo getLockInfo() {  | 
|
return lock;  | 
|
}  | 
|
    /** | 
|
     * Returns the {@link LockInfo#toString string representation} | 
|
     * of an object for which the thread associated with this | 
|
     * <tt>ThreadInfo</tt> is blocked waiting. | 
|
     * This method is equivalent to calling: | 
|
     * <blockquote> | 
|
     * <pre> | 
|
     * getLockInfo().toString() | 
|
     * </pre></blockquote> | 
|
     * | 
|
     * <p>This method will return <tt>null</tt> if this thread is not blocked | 
|
     * waiting for any object or if the object is not owned by any thread. | 
|
     * | 
|
     * @return the string representation of the object on which | 
|
     * the thread is blocked if any; | 
|
     * <tt>null</tt> otherwise. | 
|
     * | 
|
     * @see #getLockInfo | 
|
*/  | 
|
public String getLockName() {  | 
|
return lockName;  | 
|
}  | 
|
    /** | 
|
     * Returns the ID of the thread which owns the object | 
|
     * for which the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is blocked waiting. | 
|
     * This method will return <tt>-1</tt> if this thread is not blocked | 
|
     * waiting for any object or if the object is not owned by any thread. | 
|
     * | 
|
     * @return the thread ID of the owner thread of the object | 
|
     * this thread is blocked on; | 
|
     * <tt>-1</tt> if this thread is not blocked | 
|
     * or if the object is not owned by any thread. | 
|
     * | 
|
     * @see #getLockInfo | 
|
*/  | 
|
    public long getLockOwnerId() { | 
|
return lockOwnerId;  | 
|
}  | 
|
    /** | 
|
     * Returns the name of the thread which owns the object | 
|
     * for which the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is blocked waiting. | 
|
     * This method will return <tt>null</tt> if this thread is not blocked | 
|
     * waiting for any object or if the object is not owned by any thread. | 
|
     * | 
|
     * @return the name of the thread that owns the object | 
|
     * this thread is blocked on; | 
|
     * <tt>null</tt> if this thread is not blocked | 
|
     * or if the object is not owned by any thread. | 
|
     * | 
|
     * @see #getLockInfo | 
|
*/  | 
|
public String getLockOwnerName() {  | 
|
return lockOwnerName;  | 
|
}  | 
|
    /** | 
|
     * Returns the stack trace of the thread | 
|
     * associated with this <tt>ThreadInfo</tt>. | 
|
     * If no stack trace was requested for this thread info, this method | 
|
     * will return a zero-length array. | 
|
     * If the returned array is of non-zero length then the first element of | 
|
     * the array represents the top of the stack, which is the most recent | 
|
     * method invocation in the sequence.  The last element of the array | 
|
     * represents the bottom of the stack, which is the least recent method | 
|
     * invocation in the sequence. | 
|
     * | 
|
     * <p>Some Java virtual machines may, under some circumstances, omit one | 
|
     * or more stack frames from the stack trace.  In the extreme case, | 
|
     * a virtual machine that has no stack trace information concerning | 
|
     * the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is permitted to return a zero-length array from this method. | 
|
     * | 
|
     * @return an array of <tt>StackTraceElement</tt> objects of the thread. | 
|
*/  | 
|
public StackTraceElement[] getStackTrace() {  | 
|
return stackTrace;  | 
|
}  | 
|
    /** | 
|
     * Tests if the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is suspended.  This method returns <tt>true</tt> if | 
|
     * {@link Thread#suspend} has been called. | 
|
     * | 
|
     * @return <tt>true</tt> if the thread is suspended; | 
|
     *         <tt>false</tt> otherwise. | 
|
*/  | 
|
    public boolean isSuspended() { | 
|
return suspended;  | 
|
}  | 
|
    /** | 
|
     * Tests if the thread associated with this <tt>ThreadInfo</tt> | 
|
     * is executing native code via the Java Native Interface (JNI). | 
|
     * The JNI native code does not include | 
|
     * the virtual machine support code or the compiled native | 
|
     * code generated by the virtual machine. | 
|
     * | 
|
     * @return <tt>true</tt> if the thread is executing native code; | 
|
     *         <tt>false</tt> otherwise. | 
|
*/  | 
|
    public boolean isInNative() { | 
|
return inNative;  | 
|
}  | 
|
    /** | 
|
     * Returns a string representation of this thread info. | 
|
     * The format of this string depends on the implementation. | 
|
     * The returned string will typically include | 
|
     * the {@linkplain #getThreadName thread name}, | 
|
     * the {@linkplain #getThreadId thread ID}, | 
|
     * its {@linkplain #getThreadState state}, | 
|
     * and a {@linkplain #getStackTrace stack trace} if any. | 
|
     * | 
|
     * @return a string representation of this thread info. | 
|
*/  | 
|
public String toString() {  | 
|
StringBuilder sb = new StringBuilder("\"" + getThreadName() + "\"" +  | 
|
" Id=" + getThreadId() + " " +  | 
|
getThreadState());  | 
|
if (getLockName() != null) {  | 
|
sb.append(" on " + getLockName());  | 
|
}  | 
|
if (getLockOwnerName() != null) {  | 
|
sb.append(" owned by \"" + getLockOwnerName() +  | 
|
"\" Id=" + getLockOwnerId());  | 
|
}  | 
|
if (isSuspended()) {  | 
|
sb.append(" (suspended)");  | 
|
}  | 
|
if (isInNative()) {  | 
|
sb.append(" (in native)");  | 
|
}  | 
|
sb.append('\n');  | 
|
int i = 0;  | 
|
for (; i < stackTrace.length && i < MAX_FRAMES; i++) {  | 
|
StackTraceElement ste = stackTrace[i];  | 
|
sb.append("\tat " + ste.toString());  | 
|
sb.append('\n');  | 
|
if (i == 0 && getLockInfo() != null) {  | 
|
Thread.State ts = getThreadState();  | 
|
switch (ts) {  | 
|
case BLOCKED:  | 
|
sb.append("\t- blocked on " + getLockInfo());  | 
|
sb.append('\n');  | 
|
break;  | 
|
case WAITING:  | 
|
sb.append("\t- waiting on " + getLockInfo());  | 
|
sb.append('\n');  | 
|
break;  | 
|
case TIMED_WAITING:  | 
|
sb.append("\t- waiting on " + getLockInfo());  | 
|
sb.append('\n');  | 
|
break;  | 
|
default:  | 
|
}  | 
|
}  | 
|
for (MonitorInfo mi : lockedMonitors) {  | 
|
if (mi.getLockedStackDepth() == i) {  | 
|
sb.append("\t- locked " + mi);  | 
|
sb.append('\n');  | 
|
}  | 
|
}  | 
|
}  | 
|
if (i < stackTrace.length) {  | 
|
sb.append("\t...");  | 
|
sb.append('\n');  | 
|
}  | 
|
LockInfo[] locks = getLockedSynchronizers();  | 
|
if (locks.length > 0) {  | 
|
sb.append("\n\tNumber of locked synchronizers = " + locks.length);  | 
|
sb.append('\n');  | 
|
for (LockInfo li : locks) {  | 
|
sb.append("\t- " + li);  | 
|
sb.append('\n');  | 
|
}  | 
|
}  | 
|
sb.append('\n');  | 
|
return sb.toString();  | 
|
}  | 
|
private static final int MAX_FRAMES = 8;  | 
|
    /** | 
|
     * Returns a <tt>ThreadInfo</tt> object represented by the | 
|
     * given <tt>CompositeData</tt>. | 
|
     * The given <tt>CompositeData</tt> must contain the following attributes | 
|
     * unless otherwise specified below: | 
|
     * <blockquote> | 
|
     * <table border summary="The attributes and their types the given CompositeData contains"> | 
|
     * <tr> | 
|
     *   <th align=left>Attribute Name</th> | 
|
     *   <th align=left>Type</th> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>threadId</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>threadName</td> | 
|
     *   <td><tt>java.lang.String</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>threadState</td> | 
|
     *   <td><tt>java.lang.String</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>suspended</td> | 
|
     *   <td><tt>java.lang.Boolean</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>inNative</td> | 
|
     *   <td><tt>java.lang.Boolean</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>blockedCount</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>blockedTime</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>waitedCount</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>waitedTime</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockInfo</td> | 
|
     *   <td><tt>javax.management.openmbean.CompositeData</tt> | 
|
     *       - the mapped type for {@link LockInfo} as specified in the | 
|
     *         {@link LockInfo#from} method. | 
|
     *       <p> | 
|
     *       If <tt>cd</tt> does not contain this attribute, | 
|
     *       the <tt>LockInfo</tt> object will be constructed from | 
|
     *       the value of the <tt>lockName</tt> attribute. </td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockName</td> | 
|
     *   <td><tt>java.lang.String</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockOwnerId</td> | 
|
     *   <td><tt>java.lang.Long</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockOwnerName</td> | 
|
     *   <td><tt>java.lang.String</tt></td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td><a name="StackTrace">stackTrace</a></td> | 
|
     *   <td><tt>javax.management.openmbean.CompositeData[]</tt> | 
|
     *       <p> | 
|
     *       Each element is a <tt>CompositeData</tt> representing | 
|
     *       StackTraceElement containing the following attributes: | 
|
     *       <blockquote> | 
|
     *       <table cellspacing=1 cellpadding=0 summary="The attributes and their types the given CompositeData contains"> | 
|
     *       <tr> | 
|
     *         <th align=left>Attribute Name</th> | 
|
     *         <th align=left>Type</th> | 
|
     *       </tr> | 
|
     *       <tr> | 
|
     *         <td>className</td> | 
|
     *         <td><tt>java.lang.String</tt></td> | 
|
     *       </tr> | 
|
     *       <tr> | 
|
     *         <td>methodName</td> | 
|
     *         <td><tt>java.lang.String</tt></td> | 
|
     *       </tr> | 
|
     *       <tr> | 
|
     *         <td>fileName</td> | 
|
     *         <td><tt>java.lang.String</tt></td> | 
|
     *       </tr> | 
|
     *       <tr> | 
|
     *         <td>lineNumber</td> | 
|
     *         <td><tt>java.lang.Integer</tt></td> | 
|
     *       </tr> | 
|
     *       <tr> | 
|
     *         <td>nativeMethod</td> | 
|
     *         <td><tt>java.lang.Boolean</tt></td> | 
|
     *       </tr> | 
|
     *       </table> | 
|
     *       </blockquote> | 
|
     *   </td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockedMonitors</td> | 
|
     *   <td><tt>javax.management.openmbean.CompositeData[]</tt> | 
|
     *       whose element type is the mapped type for | 
|
     *       {@link MonitorInfo} as specified in the | 
|
     *       {@link MonitorInfo#from Monitor.from} method. | 
|
     *       <p> | 
|
     *       If <tt>cd</tt> does not contain this attribute, | 
|
     *       this attribute will be set to an empty array. </td> | 
|
     * </tr> | 
|
     * <tr> | 
|
     *   <td>lockedSynchronizers</td> | 
|
     *   <td><tt>javax.management.openmbean.CompositeData[]</tt> | 
|
     *       whose element type is the mapped type for | 
|
     *       {@link LockInfo} as specified in the {@link LockInfo#from} method. | 
|
     *       <p> | 
|
     *       If <tt>cd</tt> does not contain this attribute, | 
|
     *       this attribute will be set to an empty array. </td> | 
|
     * </tr> | 
|
     * </table> | 
|
     * </blockquote> | 
|
     * | 
|
     * @param cd <tt>CompositeData</tt> representing a <tt>ThreadInfo</tt> | 
|
     * | 
|
     * @throws IllegalArgumentException if <tt>cd</tt> does not | 
|
     *   represent a <tt>ThreadInfo</tt> with the attributes described | 
|
     *   above. | 
|
     * | 
|
     * @return a <tt>ThreadInfo</tt> object represented | 
|
     *         by <tt>cd</tt> if <tt>cd</tt> is not <tt>null</tt>; | 
|
     *         <tt>null</tt> otherwise. | 
|
*/  | 
|
public static ThreadInfo from(CompositeData cd) {  | 
|
if (cd == null) {  | 
|
return null;  | 
|
}  | 
|
if (cd instanceof ThreadInfoCompositeData) {  | 
|
return ((ThreadInfoCompositeData) cd).getThreadInfo();  | 
|
        } else { | 
|
return new ThreadInfo(cd);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an array of {@link MonitorInfo} objects, each of which | 
|
     * represents an object monitor currently locked by the thread | 
|
     * associated with this <tt>ThreadInfo</tt>. | 
|
     * If no locked monitor was requested for this thread info or | 
|
     * no monitor is locked by the thread, this method | 
|
     * will return a zero-length array. | 
|
     * | 
|
     * @return an array of <tt>MonitorInfo</tt> objects representing | 
|
     *         the object monitors locked by the thread. | 
|
     * | 
|
     * @since 1.6 | 
|
*/  | 
|
public MonitorInfo[] getLockedMonitors() {  | 
|
return lockedMonitors;  | 
|
}  | 
|
    /** | 
|
     * Returns an array of {@link LockInfo} objects, each of which | 
|
     * represents an <a href="LockInfo.html#OwnableSynchronizer">ownable | 
|
     * synchronizer</a> currently locked by the thread associated with | 
|
     * this <tt>ThreadInfo</tt>.  If no locked synchronizer was | 
|
     * requested for this thread info or no synchronizer is locked by | 
|
     * the thread, this method will return a zero-length array. | 
|
     * | 
|
     * @return an array of <tt>LockInfo</tt> objects representing | 
|
     *         the ownable synchronizers locked by the thread. | 
|
     * | 
|
     * @since 1.6 | 
|
*/  | 
|
public LockInfo[] getLockedSynchronizers() {  | 
|
return lockedSynchronizers;  | 
|
}  | 
|
private static final StackTraceElement[] NO_STACK_TRACE =  | 
|
new StackTraceElement[0];  | 
|
}  |