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