View Javadoc
1   /*
2    * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package java.lang.management;
27  
28  import javax.management.openmbean.CompositeData;
29  import sun.management.ManagementFactoryHelper;
30  import sun.management.ThreadInfoCompositeData;
31  import static java.lang.Thread.State.*;
32  
33  /**
34   * Thread information. <tt>ThreadInfo</tt> contains the information
35   * about a thread including:
36   * <h3>General thread information</h3>
37   * <ul>
38   *   <li>Thread ID.</li>
39   *   <li>Name of the thread.</li>
40   * </ul>
41   *
42   * <h3>Execution information</h3>
43   * <ul>
44   *   <li>Thread state.</li>
45   *   <li>The object upon which the thread is blocked due to:
46   *       <ul>
47   *       <li>waiting to enter a synchronization block/method, or</li>
48   *       <li>waiting to be notified in a {@link Object#wait Object.wait} method,
49   *           or</li>
50   *       <li>parking due to a {@link java.util.concurrent.locks.LockSupport#park
51   *           LockSupport.park} call.</li>
52   *       </ul>
53   *   </li>
54   *   <li>The ID of the thread that owns the object
55   *       that the thread is blocked.</li>
56   *   <li>Stack trace of the thread.</li>
57   *   <li>List of object monitors locked by the thread.</li>
58   *   <li>List of <a href="LockInfo.html#OwnableSynchronizer">
59   *       ownable synchronizers</a> locked by the thread.</li>
60   * </ul>
61   *
62   * <h4><a name="SyncStats">Synchronization Statistics</a></h4>
63   * <ul>
64   *   <li>The number of times that the thread has blocked for
65   *       synchronization or waited for notification.</li>
66   *   <li>The accumulated elapsed time that the thread has blocked
67   *       for synchronization or waited for notification
68   *       since {@link ThreadMXBean#setThreadContentionMonitoringEnabled
69   *       thread contention monitoring}
70   *       was enabled. Some Java virtual machine implementation
71   *       may not support this.  The
72   *       {@link ThreadMXBean#isThreadContentionMonitoringSupported()}
73   *       method can be used to determine if a Java virtual machine
74   *       supports this.</li>
75   * </ul>
76   *
77   * <p>This thread information class is designed for use in monitoring of
78   * the system, not for synchronization control.
79   *
80   * <h4>MXBean Mapping</h4>
81   * <tt>ThreadInfo</tt> is mapped to a {@link CompositeData CompositeData}
82   * with attributes as specified in
83   * the {@link #from from} method.
84   *
85   * @see ThreadMXBean#getThreadInfo
86   * @see ThreadMXBean#dumpAllThreads
87   *
88   * @author  Mandy Chung
89   * @since   1.5
90   */
91  
92  public class ThreadInfo {
93      private String       threadName;
94      private long         threadId;
95      private long         blockedTime;
96      private long         blockedCount;
97      private long         waitedTime;
98      private long         waitedCount;
99      private LockInfo     lock;
100     private String       lockName;
101     private long         lockOwnerId;
102     private String       lockOwnerName;
103     private boolean      inNative;
104     private boolean      suspended;
105     private Thread.State threadState;
106     private StackTraceElement[] stackTrace;
107     private MonitorInfo[]       lockedMonitors;
108     private LockInfo[]          lockedSynchronizers;
109 
110     private static MonitorInfo[] EMPTY_MONITORS = new MonitorInfo[0];
111     private static LockInfo[] EMPTY_SYNCS = new LockInfo[0];
112 
113     /**
114      * Constructor of ThreadInfo created by the JVM
115      *
116      * @param t             Thread
117      * @param state         Thread state
118      * @param lockObj       Object on which the thread is blocked
119      * @param lockOwner     the thread holding the lock
120      * @param blockedCount  Number of times blocked to enter a lock
121      * @param blockedTime   Approx time blocked to enter a lock
122      * @param waitedCount   Number of times waited on a lock
123      * @param waitedTime    Approx time waited on a lock
124      * @param stackTrace    Thread stack trace
125      */
126     private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,
127                        long blockedCount, long blockedTime,
128                        long waitedCount, long waitedTime,
129                        StackTraceElement[] stackTrace) {
130         initialize(t, state, lockObj, lockOwner,
131                    blockedCount, blockedTime,
132                    waitedCount, waitedTime, stackTrace,
133                    EMPTY_MONITORS, EMPTY_SYNCS);
134     }
135 
136     /**
137      * Constructor of ThreadInfo created by the JVM
138      * for {@link ThreadMXBean#getThreadInfo(long[],boolean,boolean)}
139      * and {@link ThreadMXBean#dumpAllThreads}
140      *
141      * @param t             Thread
142      * @param state         Thread state
143      * @param lockObj       Object on which the thread is blocked
144      * @param lockOwner     the thread holding the lock
145      * @param blockedCount  Number of times blocked to enter a lock
146      * @param blockedTime   Approx time blocked to enter a lock
147      * @param waitedCount   Number of times waited on a lock
148      * @param waitedTime    Approx time waited on a lock
149      * @param stackTrace    Thread stack trace
150      * @param monitors      List of locked monitors
151      * @param stackDepths   List of stack depths
152      * @param synchronizers List of locked synchronizers
153      */
154     private ThreadInfo(Thread t, int state, Object lockObj, Thread lockOwner,
155                        long blockedCount, long blockedTime,
156                        long waitedCount, long waitedTime,
157                        StackTraceElement[] stackTrace,
158                        Object[] monitors,
159                        int[] stackDepths,
160                        Object[] synchronizers) {
161         int numMonitors = (monitors == null ? 0 : monitors.length);
162         MonitorInfo[] lockedMonitors;
163         if (numMonitors == 0) {
164             lockedMonitors = EMPTY_MONITORS;
165         } else {
166             lockedMonitors = new MonitorInfo[numMonitors];
167             for (int i = 0; i < numMonitors; i++) {
168                 Object lock = monitors[i];
169                 String className = lock.getClass().getName();
170                 int identityHashCode = System.identityHashCode(lock);
171                 int depth = stackDepths[i];
172                 StackTraceElement ste = (depth >= 0 ? stackTrace[depth]
173                                                     : null);
174                 lockedMonitors[i] = new MonitorInfo(className,
175                                                     identityHashCode,
176                                                     depth,
177                                                     ste);
178             }
179         }
180 
181         int numSyncs = (synchronizers == null ? 0 : synchronizers.length);
182         LockInfo[] lockedSynchronizers;
183         if (numSyncs == 0) {
184             lockedSynchronizers = EMPTY_SYNCS;
185         } else {
186             lockedSynchronizers = new LockInfo[numSyncs];
187             for (int i = 0; i < numSyncs; i++) {
188                 Object lock = synchronizers[i];
189                 String className = lock.getClass().getName();
190                 int identityHashCode = System.identityHashCode(lock);
191                 lockedSynchronizers[i] = new LockInfo(className,
192                                                       identityHashCode);
193             }
194         }
195 
196         initialize(t, state, lockObj, lockOwner,
197                    blockedCount, blockedTime,
198                    waitedCount, waitedTime, stackTrace,
199                    lockedMonitors, lockedSynchronizers);
200     }
201 
202     /**
203      * Initialize ThreadInfo object
204      *
205      * @param t             Thread
206      * @param state         Thread state
207      * @param lockObj       Object on which the thread is blocked
208      * @param lockOwner     the thread holding the lock
209      * @param blockedCount  Number of times blocked to enter a lock
210      * @param blockedTime   Approx time blocked to enter a lock
211      * @param waitedCount   Number of times waited on a lock
212      * @param waitedTime    Approx time waited on a lock
213      * @param stackTrace    Thread stack trace
214      * @param lockedMonitors List of locked monitors
215      * @param lockedSynchronizers List of locked synchronizers
216      */
217     private void initialize(Thread t, int state, Object lockObj, Thread lockOwner,
218                             long blockedCount, long blockedTime,
219                             long waitedCount, long waitedTime,
220                             StackTraceElement[] stackTrace,
221                             MonitorInfo[] lockedMonitors,
222                             LockInfo[] lockedSynchronizers) {
223         this.threadId = t.getId();
224         this.threadName = t.getName();
225         this.threadState = ManagementFactoryHelper.toThreadState(state);
226         this.suspended = ManagementFactoryHelper.isThreadSuspended(state);
227         this.inNative = ManagementFactoryHelper.isThreadRunningNative(state);
228         this.blockedCount = blockedCount;
229         this.blockedTime = blockedTime;
230         this.waitedCount = waitedCount;
231         this.waitedTime = waitedTime;
232 
233         if (lockObj == null) {
234             this.lock = null;
235             this.lockName = null;
236         } else {
237             this.lock = new LockInfo(lockObj);
238             this.lockName =
239                 lock.getClassName() + '@' +
240                     Integer.toHexString(lock.getIdentityHashCode());
241         }
242         if (lockOwner == null) {
243             this.lockOwnerId = -1;
244             this.lockOwnerName = null;
245         } else {
246             this.lockOwnerId = lockOwner.getId();
247             this.lockOwnerName = lockOwner.getName();
248         }
249         if (stackTrace == null) {
250             this.stackTrace = NO_STACK_TRACE;
251         } else {
252             this.stackTrace = stackTrace;
253         }
254         this.lockedMonitors = lockedMonitors;
255         this.lockedSynchronizers = lockedSynchronizers;
256     }
257 
258     /*
259      * Constructs a <tt>ThreadInfo</tt> object from a
260      * {@link CompositeData CompositeData}.
261      */
262     private ThreadInfo(CompositeData cd) {
263         ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd);
264 
265         threadId = ticd.threadId();
266         threadName = ticd.threadName();
267         blockedTime = ticd.blockedTime();
268         blockedCount = ticd.blockedCount();
269         waitedTime = ticd.waitedTime();
270         waitedCount = ticd.waitedCount();
271         lockName = ticd.lockName();
272         lockOwnerId = ticd.lockOwnerId();
273         lockOwnerName = ticd.lockOwnerName();
274         threadState = ticd.threadState();
275         suspended = ticd.suspended();
276         inNative = ticd.inNative();
277         stackTrace = ticd.stackTrace();
278 
279         // 6.0 attributes
280         if (ticd.isCurrentVersion()) {
281             lock = ticd.lockInfo();
282             lockedMonitors = ticd.lockedMonitors();
283             lockedSynchronizers = ticd.lockedSynchronizers();
284         } else {
285             // lockInfo is a new attribute added in 1.6 ThreadInfo
286             // If cd is a 5.0 version, construct the LockInfo object
287             //  from the lockName value.
288             if (lockName != null) {
289                 String result[] = lockName.split("@");
290                 if (result.length == 2) {
291                     int identityHashCode = Integer.parseInt(result[1], 16);
292                     lock = new LockInfo(result[0], identityHashCode);
293                 } else {
294                     assert result.length == 2;
295                     lock = null;
296                 }
297             } else {
298                 lock = null;
299             }
300             lockedMonitors = EMPTY_MONITORS;
301             lockedSynchronizers = EMPTY_SYNCS;
302         }
303     }
304 
305     /**
306      * Returns the ID of the thread associated with this <tt>ThreadInfo</tt>.
307      *
308      * @return the ID of the associated thread.
309      */
310     public long getThreadId() {
311         return threadId;
312     }
313 
314     /**
315      * Returns the name of the thread associated with this <tt>ThreadInfo</tt>.
316      *
317      * @return the name of the associated thread.
318      */
319     public String getThreadName() {
320         return threadName;
321     }
322 
323     /**
324      * Returns the state of the thread associated with this <tt>ThreadInfo</tt>.
325      *
326      * @return <tt>Thread.State</tt> of the associated thread.
327      */
328     public Thread.State getThreadState() {
329          return threadState;
330     }
331 
332     /**
333      * Returns the approximate accumulated elapsed time (in milliseconds)
334      * that the thread associated with this <tt>ThreadInfo</tt>
335      * has blocked to enter or reenter a monitor
336      * since thread contention monitoring is enabled.
337      * I.e. the total accumulated time the thread has been in the
338      * {@link java.lang.Thread.State#BLOCKED BLOCKED} state since thread
339      * contention monitoring was last enabled.
340      * This method returns <tt>-1</tt> if thread contention monitoring
341      * is disabled.
342      *
343      * <p>The Java virtual machine may measure the time with a high
344      * resolution timer.  This statistic is reset when
345      * the thread contention monitoring is reenabled.
346      *
347      * @return the approximate accumulated elapsed time in milliseconds
348      * that a thread entered the <tt>BLOCKED</tt> state;
349      * <tt>-1</tt> if thread contention monitoring is disabled.
350      *
351      * @throws java.lang.UnsupportedOperationException if the Java
352      * virtual machine does not support this operation.
353      *
354      * @see ThreadMXBean#isThreadContentionMonitoringSupported
355      * @see ThreadMXBean#setThreadContentionMonitoringEnabled
356      */
357     public long getBlockedTime() {
358         return blockedTime;
359     }
360 
361     /**
362      * Returns the total number of times that
363      * the thread associated with this <tt>ThreadInfo</tt>
364      * blocked to enter or reenter a monitor.
365      * I.e. the number of times a thread has been in the
366      * {@link java.lang.Thread.State#BLOCKED BLOCKED} state.
367      *
368      * @return the total number of times that the thread
369      * entered the <tt>BLOCKED</tt> state.
370      */
371     public long getBlockedCount() {
372         return blockedCount;
373     }
374 
375     /**
376      * Returns the approximate accumulated elapsed time (in milliseconds)
377      * that the thread associated with this <tt>ThreadInfo</tt>
378      * has waited for notification
379      * since thread contention monitoring is enabled.
380      * I.e. the total accumulated time the thread has been in the
381      * {@link java.lang.Thread.State#WAITING WAITING}
382      * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
383      * since thread contention monitoring is enabled.
384      * This method returns <tt>-1</tt> if thread contention monitoring
385      * is disabled.
386      *
387      * <p>The Java virtual machine may measure the time with a high
388      * resolution timer.  This statistic is reset when
389      * the thread contention monitoring is reenabled.
390      *
391      * @return the approximate accumulated elapsed time in milliseconds
392      * that a thread has been in the <tt>WAITING</tt> or
393      * <tt>TIMED_WAITING</tt> state;
394      * <tt>-1</tt> if thread contention monitoring is disabled.
395      *
396      * @throws java.lang.UnsupportedOperationException if the Java
397      * virtual machine does not support this operation.
398      *
399      * @see ThreadMXBean#isThreadContentionMonitoringSupported
400      * @see ThreadMXBean#setThreadContentionMonitoringEnabled
401      */
402     public long getWaitedTime() {
403         return waitedTime;
404     }
405 
406     /**
407      * Returns the total number of times that
408      * the thread associated with this <tt>ThreadInfo</tt>
409      * waited for notification.
410      * I.e. the number of times that a thread has been
411      * in the {@link java.lang.Thread.State#WAITING WAITING}
412      * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state.
413      *
414      * @return the total number of times that the thread
415      * was in the <tt>WAITING</tt> or <tt>TIMED_WAITING</tt> state.
416      */
417     public long getWaitedCount() {
418         return waitedCount;
419     }
420 
421     /**
422      * Returns the <tt>LockInfo</tt> of an object for which
423      * the thread associated with this <tt>ThreadInfo</tt>
424      * is blocked waiting.
425      * A thread can be blocked waiting for one of the following:
426      * <ul>
427      * <li>an object monitor to be acquired for entering or reentering
428      *     a synchronization block/method.
429      *     <br>The thread is in the {@link java.lang.Thread.State#BLOCKED BLOCKED}
430      *     state waiting to enter the <tt>synchronized</tt> statement
431      *     or method.
432      *     <p></li>
433      * <li>an object monitor to be notified by another thread.
434      *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
435      *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
436      *     due to a call to the {@link Object#wait Object.wait} method.
437      *     <p></li>
438      * <li>a synchronization object responsible for the thread parking.
439      *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
440      *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
441      *     due to a call to the
442      *     {@link java.util.concurrent.locks.LockSupport#park(Object)
443      *     LockSupport.park} method.  The synchronization object
444      *     is the object returned from
445      *     {@link java.util.concurrent.locks.LockSupport#getBlocker
446      *     LockSupport.getBlocker} method. Typically it is an
447      *     <a href="LockInfo.html#OwnableSynchronizer"> ownable synchronizer</a>
448      *     or a {@link java.util.concurrent.locks.Condition Condition}.</li>
449      * </ul>
450      *
451      * <p>This method returns <tt>null</tt> if the thread is not in any of
452      * the above conditions.
453      *
454      * @return <tt>LockInfo</tt> of an object for which the thread
455      *         is blocked waiting if any; <tt>null</tt> otherwise.
456      * @since 1.6
457      */
458     public LockInfo getLockInfo() {
459         return lock;
460     }
461 
462     /**
463      * Returns the {@link LockInfo#toString string representation}
464      * of an object for which the thread associated with this
465      * <tt>ThreadInfo</tt> is blocked waiting.
466      * This method is equivalent to calling:
467      * <blockquote>
468      * <pre>
469      * getLockInfo().toString()
470      * </pre></blockquote>
471      *
472      * <p>This method will return <tt>null</tt> if this thread is not blocked
473      * waiting for any object or if the object is not owned by any thread.
474      *
475      * @return the string representation of the object on which
476      * the thread is blocked if any;
477      * <tt>null</tt> otherwise.
478      *
479      * @see #getLockInfo
480      */
481     public String getLockName() {
482         return lockName;
483     }
484 
485     /**
486      * Returns the ID of the thread which owns the object
487      * for which the thread associated with this <tt>ThreadInfo</tt>
488      * is blocked waiting.
489      * This method will return <tt>-1</tt> if this thread is not blocked
490      * waiting for any object or if the object is not owned by any thread.
491      *
492      * @return the thread ID of the owner thread of the object
493      * this thread is blocked on;
494      * <tt>-1</tt> if this thread is not blocked
495      * or if the object is not owned by any thread.
496      *
497      * @see #getLockInfo
498      */
499     public long getLockOwnerId() {
500         return lockOwnerId;
501     }
502 
503     /**
504      * Returns the name of the thread which owns the object
505      * for which the thread associated with this <tt>ThreadInfo</tt>
506      * is blocked waiting.
507      * This method will return <tt>null</tt> if this thread is not blocked
508      * waiting for any object or if the object is not owned by any thread.
509      *
510      * @return the name of the thread that owns the object
511      * this thread is blocked on;
512      * <tt>null</tt> if this thread is not blocked
513      * or if the object is not owned by any thread.
514      *
515      * @see #getLockInfo
516      */
517     public String getLockOwnerName() {
518         return lockOwnerName;
519     }
520 
521     /**
522      * Returns the stack trace of the thread
523      * associated with this <tt>ThreadInfo</tt>.
524      * If no stack trace was requested for this thread info, this method
525      * will return a zero-length array.
526      * If the returned array is of non-zero length then the first element of
527      * the array represents the top of the stack, which is the most recent
528      * method invocation in the sequence.  The last element of the array
529      * represents the bottom of the stack, which is the least recent method
530      * invocation in the sequence.
531      *
532      * <p>Some Java virtual machines may, under some circumstances, omit one
533      * or more stack frames from the stack trace.  In the extreme case,
534      * a virtual machine that has no stack trace information concerning
535      * the thread associated with this <tt>ThreadInfo</tt>
536      * is permitted to return a zero-length array from this method.
537      *
538      * @return an array of <tt>StackTraceElement</tt> objects of the thread.
539      */
540     public StackTraceElement[] getStackTrace() {
541         return stackTrace;
542     }
543 
544     /**
545      * Tests if the thread associated with this <tt>ThreadInfo</tt>
546      * is suspended.  This method returns <tt>true</tt> if
547      * {@link Thread#suspend} has been called.
548      *
549      * @return <tt>true</tt> if the thread is suspended;
550      *         <tt>false</tt> otherwise.
551      */
552     public boolean isSuspended() {
553          return suspended;
554     }
555 
556     /**
557      * Tests if the thread associated with this <tt>ThreadInfo</tt>
558      * is executing native code via the Java Native Interface (JNI).
559      * The JNI native code does not include
560      * the virtual machine support code or the compiled native
561      * code generated by the virtual machine.
562      *
563      * @return <tt>true</tt> if the thread is executing native code;
564      *         <tt>false</tt> otherwise.
565      */
566     public boolean isInNative() {
567          return inNative;
568     }
569 
570     /**
571      * Returns a string representation of this thread info.
572      * The format of this string depends on the implementation.
573      * The returned string will typically include
574      * the {@linkplain #getThreadName thread name},
575      * the {@linkplain #getThreadId thread ID},
576      * its {@linkplain #getThreadState state},
577      * and a {@linkplain #getStackTrace stack trace} if any.
578      *
579      * @return a string representation of this thread info.
580      */
581     public String toString() {
582         StringBuilder sb = new StringBuilder("\"" + getThreadName() + "\"" +
583                                              " Id=" + getThreadId() + " " +
584                                              getThreadState());
585         if (getLockName() != null) {
586             sb.append(" on " + getLockName());
587         }
588         if (getLockOwnerName() != null) {
589             sb.append(" owned by \"" + getLockOwnerName() +
590                       "\" Id=" + getLockOwnerId());
591         }
592         if (isSuspended()) {
593             sb.append(" (suspended)");
594         }
595         if (isInNative()) {
596             sb.append(" (in native)");
597         }
598         sb.append('\n');
599         int i = 0;
600         for (; i < stackTrace.length && i < MAX_FRAMES; i++) {
601             StackTraceElement ste = stackTrace[i];
602             sb.append("\tat " + ste.toString());
603             sb.append('\n');
604             if (i == 0 && getLockInfo() != null) {
605                 Thread.State ts = getThreadState();
606                 switch (ts) {
607                     case BLOCKED:
608                         sb.append("\t-  blocked on " + getLockInfo());
609                         sb.append('\n');
610                         break;
611                     case WAITING:
612                         sb.append("\t-  waiting on " + getLockInfo());
613                         sb.append('\n');
614                         break;
615                     case TIMED_WAITING:
616                         sb.append("\t-  waiting on " + getLockInfo());
617                         sb.append('\n');
618                         break;
619                     default:
620                 }
621             }
622 
623             for (MonitorInfo mi : lockedMonitors) {
624                 if (mi.getLockedStackDepth() == i) {
625                     sb.append("\t-  locked " + mi);
626                     sb.append('\n');
627                 }
628             }
629        }
630        if (i < stackTrace.length) {
631            sb.append("\t...");
632            sb.append('\n');
633        }
634 
635        LockInfo[] locks = getLockedSynchronizers();
636        if (locks.length > 0) {
637            sb.append("\n\tNumber of locked synchronizers = " + locks.length);
638            sb.append('\n');
639            for (LockInfo li : locks) {
640                sb.append("\t- " + li);
641                sb.append('\n');
642            }
643        }
644        sb.append('\n');
645        return sb.toString();
646     }
647     private static final int MAX_FRAMES = 8;
648 
649     /**
650      * Returns a <tt>ThreadInfo</tt> object represented by the
651      * given <tt>CompositeData</tt>.
652      * The given <tt>CompositeData</tt> must contain the following attributes
653      * unless otherwise specified below:
654      * <blockquote>
655      * <table border summary="The attributes and their types the given CompositeData contains">
656      * <tr>
657      *   <th align=left>Attribute Name</th>
658      *   <th align=left>Type</th>
659      * </tr>
660      * <tr>
661      *   <td>threadId</td>
662      *   <td><tt>java.lang.Long</tt></td>
663      * </tr>
664      * <tr>
665      *   <td>threadName</td>
666      *   <td><tt>java.lang.String</tt></td>
667      * </tr>
668      * <tr>
669      *   <td>threadState</td>
670      *   <td><tt>java.lang.String</tt></td>
671      * </tr>
672      * <tr>
673      *   <td>suspended</td>
674      *   <td><tt>java.lang.Boolean</tt></td>
675      * </tr>
676      * <tr>
677      *   <td>inNative</td>
678      *   <td><tt>java.lang.Boolean</tt></td>
679      * </tr>
680      * <tr>
681      *   <td>blockedCount</td>
682      *   <td><tt>java.lang.Long</tt></td>
683      * </tr>
684      * <tr>
685      *   <td>blockedTime</td>
686      *   <td><tt>java.lang.Long</tt></td>
687      * </tr>
688      * <tr>
689      *   <td>waitedCount</td>
690      *   <td><tt>java.lang.Long</tt></td>
691      * </tr>
692      * <tr>
693      *   <td>waitedTime</td>
694      *   <td><tt>java.lang.Long</tt></td>
695      * </tr>
696      * <tr>
697      *   <td>lockInfo</td>
698      *   <td><tt>javax.management.openmbean.CompositeData</tt>
699      *       - the mapped type for {@link LockInfo} as specified in the
700      *         {@link LockInfo#from} method.
701      *       <p>
702      *       If <tt>cd</tt> does not contain this attribute,
703      *       the <tt>LockInfo</tt> object will be constructed from
704      *       the value of the <tt>lockName</tt> attribute. </td>
705      * </tr>
706      * <tr>
707      *   <td>lockName</td>
708      *   <td><tt>java.lang.String</tt></td>
709      * </tr>
710      * <tr>
711      *   <td>lockOwnerId</td>
712      *   <td><tt>java.lang.Long</tt></td>
713      * </tr>
714      * <tr>
715      *   <td>lockOwnerName</td>
716      *   <td><tt>java.lang.String</tt></td>
717      * </tr>
718      * <tr>
719      *   <td><a name="StackTrace">stackTrace</a></td>
720      *   <td><tt>javax.management.openmbean.CompositeData[]</tt>
721      *       <p>
722      *       Each element is a <tt>CompositeData</tt> representing
723      *       StackTraceElement containing the following attributes:
724      *       <blockquote>
725      *       <table cellspacing=1 cellpadding=0 summary="The attributes and their types the given CompositeData contains">
726      *       <tr>
727      *         <th align=left>Attribute Name</th>
728      *         <th align=left>Type</th>
729      *       </tr>
730      *       <tr>
731      *         <td>className</td>
732      *         <td><tt>java.lang.String</tt></td>
733      *       </tr>
734      *       <tr>
735      *         <td>methodName</td>
736      *         <td><tt>java.lang.String</tt></td>
737      *       </tr>
738      *       <tr>
739      *         <td>fileName</td>
740      *         <td><tt>java.lang.String</tt></td>
741      *       </tr>
742      *       <tr>
743      *         <td>lineNumber</td>
744      *         <td><tt>java.lang.Integer</tt></td>
745      *       </tr>
746      *       <tr>
747      *         <td>nativeMethod</td>
748      *         <td><tt>java.lang.Boolean</tt></td>
749      *       </tr>
750      *       </table>
751      *       </blockquote>
752      *   </td>
753      * </tr>
754      * <tr>
755      *   <td>lockedMonitors</td>
756      *   <td><tt>javax.management.openmbean.CompositeData[]</tt>
757      *       whose element type is the mapped type for
758      *       {@link MonitorInfo} as specified in the
759      *       {@link MonitorInfo#from Monitor.from} method.
760      *       <p>
761      *       If <tt>cd</tt> does not contain this attribute,
762      *       this attribute will be set to an empty array. </td>
763      * </tr>
764      * <tr>
765      *   <td>lockedSynchronizers</td>
766      *   <td><tt>javax.management.openmbean.CompositeData[]</tt>
767      *       whose element type is the mapped type for
768      *       {@link LockInfo} as specified in the {@link LockInfo#from} method.
769      *       <p>
770      *       If <tt>cd</tt> does not contain this attribute,
771      *       this attribute will be set to an empty array. </td>
772      * </tr>
773      * </table>
774      * </blockquote>
775      *
776      * @param cd <tt>CompositeData</tt> representing a <tt>ThreadInfo</tt>
777      *
778      * @throws IllegalArgumentException if <tt>cd</tt> does not
779      *   represent a <tt>ThreadInfo</tt> with the attributes described
780      *   above.
781      *
782      * @return a <tt>ThreadInfo</tt> object represented
783      *         by <tt>cd</tt> if <tt>cd</tt> is not <tt>null</tt>;
784      *         <tt>null</tt> otherwise.
785      */
786     public static ThreadInfo from(CompositeData cd) {
787         if (cd == null) {
788             return null;
789         }
790 
791         if (cd instanceof ThreadInfoCompositeData) {
792             return ((ThreadInfoCompositeData) cd).getThreadInfo();
793         } else {
794             return new ThreadInfo(cd);
795         }
796     }
797 
798     /**
799      * Returns an array of {@link MonitorInfo} objects, each of which
800      * represents an object monitor currently locked by the thread
801      * associated with this <tt>ThreadInfo</tt>.
802      * If no locked monitor was requested for this thread info or
803      * no monitor is locked by the thread, this method
804      * will return a zero-length array.
805      *
806      * @return an array of <tt>MonitorInfo</tt> objects representing
807      *         the object monitors locked by the thread.
808      *
809      * @since 1.6
810      */
811     public MonitorInfo[] getLockedMonitors() {
812         return lockedMonitors;
813     }
814 
815     /**
816      * Returns an array of {@link LockInfo} objects, each of which
817      * represents an <a href="LockInfo.html#OwnableSynchronizer">ownable
818      * synchronizer</a> currently locked by the thread associated with
819      * this <tt>ThreadInfo</tt>.  If no locked synchronizer was
820      * requested for this thread info or no synchronizer is locked by
821      * the thread, this method will return a zero-length array.
822      *
823      * @return an array of <tt>LockInfo</tt> objects representing
824      *         the ownable synchronizers locked by the thread.
825      *
826      * @since 1.6
827      */
828     public LockInfo[] getLockedSynchronizers() {
829         return lockedSynchronizers;
830     }
831 
832     private static final StackTraceElement[] NO_STACK_TRACE =
833         new StackTraceElement[0];
834 }