/*
* Copyright (c) 2003, 2019, 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.ArrayType;
import javax.management.openmbean.CompositeData;
import sun.management.ManagementFactoryHelper;
import sun.management.ThreadInfoCompositeData;
import static java.lang.Thread.State.*;
/**
* Thread information. {@code ThreadInfo} contains the information
* about a thread including:
* <h2>General thread information</h2>
* <ul>
* <li>Thread ID.</li>
* <li>Name of the thread.</li>
* <li>Whether a thread is a daemon thread</li>
* </ul>
*
* <h2>Execution information</h2>
* <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>
* <li>Thread priority</li>
* </ul>
*
* <h3><a id="SyncStats">Synchronization Statistics</a></h3>
* <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.
*
* <h3>MXBean Mapping</h3>
* {@code ThreadInfo} 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 daemon;
private boolean inNative;
private boolean suspended;
private Thread.State threadState;
private int priority;
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;
this.daemon = t.isDaemon();
this.priority = t.getPriority();
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 {@code ThreadInfo} object from a
* {@link CompositeData CompositeData}.
*
* @throws IllegalArgumentException if the given CompositeData does not
* contain all of the attributes defined for ThreadInfo of version <= N.
*
* @see ThreadInfo#from
*/
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();
lock = ticd.lockInfo();
lockedMonitors = ticd.lockedMonitors();
lockedSynchronizers = ticd.lockedSynchronizers();
daemon = ticd.isDaemon();
priority = ticd.getPriority();
}
/**
* Returns the ID of the thread associated with this {@code ThreadInfo}.
*
* @return the ID of the associated thread.
*/
public long getThreadId() {
return threadId;
}
/**
* Returns the name of the thread associated with this {@code ThreadInfo}.
*
* @return the name of the associated thread.
*/
public String getThreadName() {
return threadName;
}
/**
* Returns the state of the thread associated with this {@code ThreadInfo}.
*
* @return {@code Thread.State} of the associated thread.
*/
public Thread.State getThreadState() {
return threadState;
}
/**
* Returns the approximate accumulated elapsed time (in milliseconds)
* that the thread associated with this {@code ThreadInfo}
* 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 {@code -1} 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 {@code BLOCKED} state;
* {@code -1} 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 {@code ThreadInfo}
* 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 {@code BLOCKED} state.
*/
public long getBlockedCount() {
return blockedCount;
}
/**
* Returns the approximate accumulated elapsed time (in milliseconds)
* that the thread associated with this {@code ThreadInfo}
* 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 {@code -1} 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 {@code WAITING} or
* {@code TIMED_WAITING} state;
* {@code -1} 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 {@code ThreadInfo}
* 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 {@code WAITING} or {@code TIMED_WAITING} state.
*/
public long getWaitedCount() {
return waitedCount;
}
/**
* Returns the {@code LockInfo} of an object for which
* the thread associated with this {@code ThreadInfo}
* 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 {@code synchronized} statement
* or method.
* </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.
* </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 {@code null} if the thread is not in any of
* the above conditions.
*
* @return {@code LockInfo} of an object for which the thread
* is blocked waiting if any; {@code null} 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
* {@code ThreadInfo} is blocked waiting.
* This method is equivalent to calling:
* <blockquote>
* <pre>
* getLockInfo().toString()
* </pre></blockquote>
*
* <p>This method will return {@code null} 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;
* {@code null} 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 {@code ThreadInfo}
* is blocked waiting.
* This method will return {@code -1} 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;
* {@code -1} 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 {@code ThreadInfo}
* is blocked waiting.
* This method will return {@code null} 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;
* {@code null} 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 {@code ThreadInfo}.
* 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 {@code ThreadInfo}
* is permitted to return a zero-length array from this method.
*
* @return an array of {@code StackTraceElement} objects of the thread.
*/
public StackTraceElement[] getStackTrace() {
return stackTrace.clone();
}
/**
* Tests if the thread associated with this {@code ThreadInfo}
* is suspended. This method returns {@code true} if
* {@link Thread#suspend} has been called.
*
* @return {@code true} if the thread is suspended;
* {@code false} otherwise.
*/
public boolean isSuspended() {
return suspended;
}
/**
* Tests if the thread associated with this {@code ThreadInfo}
* 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 {@code true} if the thread is executing native code;
* {@code false} otherwise.
*/
public boolean isInNative() {
return inNative;
}
/**
* Tests if the thread associated with this {@code ThreadInfo} is
* a {@linkplain Thread#isDaemon daemon thread}.
*
* @return {@code true} if the thread is a daemon thread,
* {@code false} otherwise.
* @see Thread#isDaemon
* @since 9
*/
public boolean isDaemon() {
return daemon;
}
/**
* Returns the {@linkplain Thread#getPriority() thread priority} of the
* thread associated with this {@code ThreadInfo}.
*
* @return The priority of the thread associated with this
* {@code ThreadInfo}.
* @since 9
*/
public int getPriority() {
return priority;
}
/**
* 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() + "\"" +
(daemon ? " daemon" : "") +
" prio=" + priority +
" 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 {@code ThreadInfo} object represented by the
* given {@code CompositeData}.
*
* <a id="attributes"></a>
* A {@code CompositeData} representing a {@code ThreadInfo} of
* version <em>N</em> must contain all of the attributes defined
* in version ≤ <em>N</em> unless specified otherwise.
* The same rule applies the composite type of the given
* {@code CompositeData} and transitively to attributes whose
* {@linkplain CompositeData#getCompositeType() type} or
* {@linkplain ArrayType#getElementOpenType() component type} is
* {@code CompositeType}.
* <p>
* A {@code CompositeData} representing {@code ThreadInfo} of
* version <em>N</em> contains {@code "stackTrace"} attribute and
* {@code "lockedMonitors"} attribute representing
* an array of {@code StackTraceElement} and
* an array of {@link MonitorInfo} respectively
* and their types are of version <em>N</em>.
* The {@code "lockedStackFrame"} attribute in
* {@link MonitorInfo#from(CompositeData) MonitorInfo}'s composite type
* must represent {@code StackTraceElement} of the same version <em>N</em>.
* Otherwise, this method will throw {@code IllegalArgumentException}.
*
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types for ThreadInfo's composite data</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* <th scope="col">Since</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">threadId</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">threadName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">threadState</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">suspended</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">inNative</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">blockedCount</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">blockedTime</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">waitedCount</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">waitedTime</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerId</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row"><a id="StackTrace">stackTrace</a></th>
* <td>{@code javax.management.openmbean.CompositeData[]}, each element
* is a {@code CompositeData} representing {@code StackTraceElement}
* as specified <a href="#stackTraceElement">below</a>.
* </td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockInfo</th>
* <td>{@code javax.management.openmbean.CompositeData}
* - the mapped type for {@link LockInfo} as specified in the
* {@link LockInfo#from} method.
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* the {@code LockInfo} object will be constructed from
* the value of the {@code lockName} attribute.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">lockedMonitors</th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* whose element type is the mapped type for
* {@link MonitorInfo} as specified in the
* {@link MonitorInfo#from MonitorInfo.from} method.
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to an empty array.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">lockedSynchronizers</th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* whose element type is the mapped type for
* {@link LockInfo} as specified in the {@link LockInfo#from} method.
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to an empty array.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">daemon</th>
* <td>{@code java.lang.Boolean}
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to {@code false}.</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">priority</th>
* <td>{@code java.lang.Integer}
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* This attribute will be set to {@link Thread#NORM_PRIORITY}.</td>
* <td>9</td>
* </tr>
* </tbody>
* </table>
*
* <a id="stackTraceElement">A {@code CompositeData} representing
* {@code StackTraceElement}</a> of version <em>N</em> must contain
* all of the attributes defined in version ≤ <em>N</em>
* unless specified otherwise.
*
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types for StackTraceElement's composite data</caption>
* <thead style="text-align:center">
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* <th scope="col">Since</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">classLoaderName</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">moduleName</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">moduleVersion</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">className</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">methodName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">fileName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lineNumber</th>
* <td>{@code java.lang.Integer}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">nativeMethod</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* </tbody>
* </table>
*
* @param cd {@code CompositeData} representing a {@code ThreadInfo}
*
* @throws IllegalArgumentException if the given {@code cd} and
* its composite type does not contain all of
* <a href="#attributes">the attributes</a> defined for a
* {@code ThreadInfo} of a specific runtime version.
*
* @return a {@code ThreadInfo} object represented
* by {@code cd} if {@code cd} is not {@code null};
* {@code null} otherwise.
*
* @revised 9
* @spec JPMS
*/
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 {@code ThreadInfo}.
* 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 {@code MonitorInfo} objects representing
* the object monitors locked by the thread.
*
* @since 1.6
*/
public MonitorInfo[] getLockedMonitors() {
return lockedMonitors.clone();
}
/**
* 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 {@code ThreadInfo}. 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 {@code LockInfo} objects representing
* the ownable synchronizers locked by the thread.
*
* @since 1.6
*/
public LockInfo[] getLockedSynchronizers() {
return lockedSynchronizers.clone();
}
private static final StackTraceElement[] NO_STACK_TRACE =
new StackTraceElement[0];
}