1 /*
   2  * Copyright (c) 2003, 2014, 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. {@code ThreadInfo} 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  *   <li>Whether a thread is a daemon thread</li>
  41  * </ul>
  42  *
  43  * <h3>Execution information</h3>
  44  * <ul>
  45  *   <li>Thread state.</li>
  46  *   <li>The object upon which the thread is blocked due to:
  47  *       <ul>
  48  *       <li>waiting to enter a synchronization block/method, or</li>
  49  *       <li>waiting to be notified in a {@link Object#wait Object.wait} method,
  50  *           or</li>
  51  *       <li>parking due to a {@link java.util.concurrent.locks.LockSupport#park
  52  *           LockSupport.park} call.</li>
  53  *       </ul>
  54  *   </li>
  55  *   <li>The ID of the thread that owns the object
  56  *       that the thread is blocked.</li>
  57  *   <li>Stack trace of the thread.</li>
  58  *   <li>List of object monitors locked by the thread.</li>
  59  *   <li>List of <a href="LockInfo.html#OwnableSynchronizer">
  60  *       ownable synchronizers</a> locked by the thread.</li>
  61  *   <li>Thread priority</li>
  62  * </ul>
  63  *
  64  * <h4><a name="SyncStats">Synchronization Statistics</a></h4>
  65  * <ul>
  66  *   <li>The number of times that the thread has blocked for
  67  *       synchronization or waited for notification.</li>
  68  *   <li>The accumulated elapsed time that the thread has blocked
  69  *       for synchronization or waited for notification
  70  *       since {@link ThreadMXBean#setThreadContentionMonitoringEnabled
  71  *       thread contention monitoring}
  72  *       was enabled. Some Java virtual machine implementation
  73  *       may not support this.  The
  74  *       {@link ThreadMXBean#isThreadContentionMonitoringSupported()}
  75  *       method can be used to determine if a Java virtual machine
  76  *       supports this.</li>
  77  * </ul>
  78  *
  79  * <p>This thread information class is designed for use in monitoring of
  80  * the system, not for synchronization control.
  81  *
  82  * <h4>MXBean Mapping</h4>
  83  * {@code ThreadInfo} is mapped to a {@link CompositeData CompositeData}
  84  * with attributes as specified in
  85  * the {@link #from from} method.
  86  *
  87  * @see ThreadMXBean#getThreadInfo
  88  * @see ThreadMXBean#dumpAllThreads
  89  *
  90  * @author  Mandy Chung
  91  * @since   1.5
  92  */
  93 
  94 public class ThreadInfo {
  95     private String       threadName;
  96     private long         threadId;
  97     private long         blockedTime;
  98     private long         blockedCount;
  99     private long         waitedTime;
 100     private long         waitedCount;
 101     private LockInfo     lock;
 102     private String       lockName;
 103     private long         lockOwnerId;
 104     private String       lockOwnerName;
 105     private boolean      daemon;
 106     private boolean      inNative;
 107     private boolean      suspended;
 108     private Thread.State threadState;
 109     private int          priority;
 110     private StackTraceElement[] stackTrace;
 111     private MonitorInfo[]       lockedMonitors;
 112     private LockInfo[]          lockedSynchronizers;
 113 
 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      */
 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      */
 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      */
 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     private ThreadInfo(CompositeData cd) {
 269         ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd);
 270 
 271         threadId = ticd.threadId();
 272         threadName = ticd.threadName();
 273         blockedTime = ticd.blockedTime();
 274         blockedCount = ticd.blockedCount();
 275         waitedTime = ticd.waitedTime();
 276         waitedCount = ticd.waitedCount();
 277         lockName = ticd.lockName();
 278         lockOwnerId = ticd.lockOwnerId();
 279         lockOwnerName = ticd.lockOwnerName();
 280         threadState = ticd.threadState();
 281         suspended = ticd.suspended();
 282         inNative = ticd.inNative();
 283         stackTrace = ticd.stackTrace();
 284 
 285         // 6.0 attributes
 286         if (ticd.hasV6()) {
 287             lock = ticd.lockInfo();
 288             lockedMonitors = ticd.lockedMonitors();
 289             lockedSynchronizers = ticd.lockedSynchronizers();
 290         } else {
 291             // lockInfo is a new attribute added in 1.6 ThreadInfo
 292             // If cd is a 5.0 version, construct the LockInfo object
 293             //  from the lockName value.
 294             if (lockName != null) {
 295                 String result[] = lockName.split("@");
 296                 if (result.length == 2) {
 297                     int identityHashCode = Integer.parseInt(result[1], 16);
 298                     lock = new LockInfo(result[0], identityHashCode);
 299                 } else {
 300                     assert result.length == 2;
 301                     lock = null;
 302                 }
 303             } else {
 304                 lock = null;
 305             }
 306             lockedMonitors = EMPTY_MONITORS;
 307             lockedSynchronizers = EMPTY_SYNCS;
 308         }
 309 
 310         // 9.0 attributes
 311         if (ticd.isCurrentVersion()) {
 312             daemon = ticd.isDaemon();
 313             priority = ticd.getPriority();
 314         } else {
 315             // Not ideal, but unclear what else we can do.
 316             daemon = false;
 317             priority = Thread.NORM_PRIORITY;
 318         }
 319     }
 320 
 321     /**
 322      * Returns the ID of the thread associated with this {@code ThreadInfo}.
 323      *
 324      * @return the ID of the associated thread.
 325      */
 326     public long getThreadId() {
 327         return threadId;
 328     }
 329 
 330     /**
 331      * Returns the name of the thread associated with this {@code ThreadInfo}.
 332      *
 333      * @return the name of the associated thread.
 334      */
 335     public String getThreadName() {
 336         return threadName;
 337     }
 338 
 339     /**
 340      * Returns the state of the thread associated with this {@code ThreadInfo}.
 341      *
 342      * @return {@code Thread.State} of the associated thread.
 343      */
 344     public Thread.State getThreadState() {
 345          return threadState;
 346     }
 347 
 348     /**
 349      * Returns the approximate accumulated elapsed time (in milliseconds)
 350      * that the thread associated with this {@code ThreadInfo}
 351      * has blocked to enter or reenter a monitor
 352      * since thread contention monitoring is enabled.
 353      * I.e. the total accumulated time the thread has been in the
 354      * {@link java.lang.Thread.State#BLOCKED BLOCKED} state since thread
 355      * contention monitoring was last enabled.
 356      * This method returns {@code -1} if thread contention monitoring
 357      * is disabled.
 358      *
 359      * <p>The Java virtual machine may measure the time with a high
 360      * resolution timer.  This statistic is reset when
 361      * the thread contention monitoring is reenabled.
 362      *
 363      * @return the approximate accumulated elapsed time in milliseconds
 364      * that a thread entered the {@code BLOCKED} state;
 365      * {@code -1} if thread contention monitoring is disabled.
 366      *
 367      * @throws java.lang.UnsupportedOperationException if the Java
 368      * virtual machine does not support this operation.
 369      *
 370      * @see ThreadMXBean#isThreadContentionMonitoringSupported
 371      * @see ThreadMXBean#setThreadContentionMonitoringEnabled
 372      */
 373     public long getBlockedTime() {
 374         return blockedTime;
 375     }
 376 
 377     /**
 378      * Returns the total number of times that
 379      * the thread associated with this {@code ThreadInfo}
 380      * blocked to enter or reenter a monitor.
 381      * I.e. the number of times a thread has been in the
 382      * {@link java.lang.Thread.State#BLOCKED BLOCKED} state.
 383      *
 384      * @return the total number of times that the thread
 385      * entered the {@code BLOCKED} state.
 386      */
 387     public long getBlockedCount() {
 388         return blockedCount;
 389     }
 390 
 391     /**
 392      * Returns the approximate accumulated elapsed time (in milliseconds)
 393      * that the thread associated with this {@code ThreadInfo}
 394      * has waited for notification
 395      * since thread contention monitoring is enabled.
 396      * I.e. the total accumulated time the thread has been in the
 397      * {@link java.lang.Thread.State#WAITING WAITING}
 398      * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
 399      * since thread contention monitoring is enabled.
 400      * This method returns {@code -1} if thread contention monitoring
 401      * is disabled.
 402      *
 403      * <p>The Java virtual machine may measure the time with a high
 404      * resolution timer.  This statistic is reset when
 405      * the thread contention monitoring is reenabled.
 406      *
 407      * @return the approximate accumulated elapsed time in milliseconds
 408      * that a thread has been in the {@code WAITING} or
 409      * {@code TIMED_WAITING} state;
 410      * {@code -1} if thread contention monitoring is disabled.
 411      *
 412      * @throws java.lang.UnsupportedOperationException if the Java
 413      * virtual machine does not support this operation.
 414      *
 415      * @see ThreadMXBean#isThreadContentionMonitoringSupported
 416      * @see ThreadMXBean#setThreadContentionMonitoringEnabled
 417      */
 418     public long getWaitedTime() {
 419         return waitedTime;
 420     }
 421 
 422     /**
 423      * Returns the total number of times that
 424      * the thread associated with this {@code ThreadInfo}
 425      * waited for notification.
 426      * I.e. the number of times that a thread has been
 427      * in the {@link java.lang.Thread.State#WAITING WAITING}
 428      * or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state.
 429      *
 430      * @return the total number of times that the thread
 431      * was in the {@code WAITING} or {@code TIMED_WAITING} state.
 432      */
 433     public long getWaitedCount() {
 434         return waitedCount;
 435     }
 436 
 437     /**
 438      * Returns the {@code LockInfo} of an object for which
 439      * the thread associated with this {@code ThreadInfo}
 440      * is blocked waiting.
 441      * A thread can be blocked waiting for one of the following:
 442      * <ul>
 443      * <li>an object monitor to be acquired for entering or reentering
 444      *     a synchronization block/method.
 445      *     <br>The thread is in the {@link java.lang.Thread.State#BLOCKED BLOCKED}
 446      *     state waiting to enter the {@code synchronized} statement
 447      *     or method.
 448      *     </li>
 449      * <li>an object monitor to be notified by another thread.
 450      *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
 451      *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
 452      *     due to a call to the {@link Object#wait Object.wait} method.
 453      *     </li>
 454      * <li>a synchronization object responsible for the thread parking.
 455      *     <br>The thread is in the {@link java.lang.Thread.State#WAITING WAITING}
 456      *     or {@link java.lang.Thread.State#TIMED_WAITING TIMED_WAITING} state
 457      *     due to a call to the
 458      *     {@link java.util.concurrent.locks.LockSupport#park(Object)
 459      *     LockSupport.park} method.  The synchronization object
 460      *     is the object returned from
 461      *     {@link java.util.concurrent.locks.LockSupport#getBlocker
 462      *     LockSupport.getBlocker} method. Typically it is an
 463      *     <a href="LockInfo.html#OwnableSynchronizer"> ownable synchronizer</a>
 464      *     or a {@link java.util.concurrent.locks.Condition Condition}.</li>
 465      * </ul>
 466      *
 467      * <p>This method returns {@code null} if the thread is not in any of
 468      * the above conditions.
 469      *
 470      * @return {@code LockInfo} of an object for which the thread
 471      *         is blocked waiting if any; {@code null} otherwise.
 472      * @since 1.6
 473      */
 474     public LockInfo getLockInfo() {
 475         return lock;
 476     }
 477 
 478     /**
 479      * Returns the {@link LockInfo#toString string representation}
 480      * of an object for which the thread associated with this
 481      * {@code ThreadInfo} is blocked waiting.
 482      * This method is equivalent to calling:
 483      * <blockquote>
 484      * <pre>
 485      * getLockInfo().toString()
 486      * </pre></blockquote>
 487      *
 488      * <p>This method will return {@code null} if this thread is not blocked
 489      * waiting for any object or if the object is not owned by any thread.
 490      *
 491      * @return the string representation of the object on which
 492      * the thread is blocked if any;
 493      * {@code null} otherwise.
 494      *
 495      * @see #getLockInfo
 496      */
 497     public String getLockName() {
 498         return lockName;
 499     }
 500 
 501     /**
 502      * Returns the ID of the thread which owns the object
 503      * for which the thread associated with this {@code ThreadInfo}
 504      * is blocked waiting.
 505      * This method will return {@code -1} if this thread is not blocked
 506      * waiting for any object or if the object is not owned by any thread.
 507      *
 508      * @return the thread ID of the owner thread of the object
 509      * this thread is blocked on;
 510      * {@code -1} if this thread is not blocked
 511      * or if the object is not owned by any thread.
 512      *
 513      * @see #getLockInfo
 514      */
 515     public long getLockOwnerId() {
 516         return lockOwnerId;
 517     }
 518 
 519     /**
 520      * Returns the name of the thread which owns the object
 521      * for which the thread associated with this {@code ThreadInfo}
 522      * is blocked waiting.
 523      * This method will return {@code null} if this thread is not blocked
 524      * waiting for any object or if the object is not owned by any thread.
 525      *
 526      * @return the name of the thread that owns the object
 527      * this thread is blocked on;
 528      * {@code null} if this thread is not blocked
 529      * or if the object is not owned by any thread.
 530      *
 531      * @see #getLockInfo
 532      */
 533     public String getLockOwnerName() {
 534         return lockOwnerName;
 535     }
 536 
 537     /**
 538      * Returns the stack trace of the thread
 539      * associated with this {@code ThreadInfo}.
 540      * If no stack trace was requested for this thread info, this method
 541      * will return a zero-length array.
 542      * If the returned array is of non-zero length then the first element of
 543      * the array represents the top of the stack, which is the most recent
 544      * method invocation in the sequence.  The last element of the array
 545      * represents the bottom of the stack, which is the least recent method
 546      * invocation in the sequence.
 547      *
 548      * <p>Some Java virtual machines may, under some circumstances, omit one
 549      * or more stack frames from the stack trace.  In the extreme case,
 550      * a virtual machine that has no stack trace information concerning
 551      * the thread associated with this {@code ThreadInfo}
 552      * is permitted to return a zero-length array from this method.
 553      *
 554      * @return an array of {@code StackTraceElement} objects of the thread.
 555      */
 556     public StackTraceElement[] getStackTrace() {
 557         return stackTrace;
 558     }
 559 
 560     /**
 561      * Tests if the thread associated with this {@code ThreadInfo}
 562      * is suspended.  This method returns {@code true} if
 563      * {@link Thread#suspend} has been called.
 564      *
 565      * @return {@code true} if the thread is suspended;
 566      *         {@code false} otherwise.
 567      */
 568     public boolean isSuspended() {
 569          return suspended;
 570     }
 571 
 572     /**
 573      * Tests if the thread associated with this {@code ThreadInfo}
 574      * is executing native code via the Java Native Interface (JNI).
 575      * The JNI native code does not include
 576      * the virtual machine support code or the compiled native
 577      * code generated by the virtual machine.
 578      *
 579      * @return {@code true} if the thread is executing native code;
 580      *         {@code false} otherwise.
 581      */
 582     public boolean isInNative() {
 583          return inNative;
 584     }
 585 
 586     /**
 587      * Tests if the thread associated with this {@code ThreadInfo} is
 588      * a {@linkplain Thread#isDaemon daemon thread}.
 589      *
 590      * @return {@code true} if the thread is a daemon thread,
 591      *         {@code false} otherwise.
 592      * @see Thread#isDaemon
 593      * @since 1.9
 594      */
 595     public boolean isDaemon() {
 596          return daemon;
 597     }
 598 
 599     /**
 600      * Returns the {@linkplain Thread#getPriority() thread priority} of the
 601      * thread associated with this {@code ThreadInfo}.
 602      *
 603      * @return The priority of the thread associated with this
 604      *         {@code ThreadInfo}.
 605      * @since 1.9
 606      */
 607     public int getPriority() {
 608          return priority;
 609     }
 610 
 611     /**
 612      * Returns a string representation of this thread info.
 613      * The format of this string depends on the implementation.
 614      * The returned string will typically include
 615      * the {@linkplain #getThreadName thread name},
 616      * the {@linkplain #getThreadId thread ID},
 617      * its {@linkplain #getThreadState state},
 618      * and a {@linkplain #getStackTrace stack trace} if any.
 619      *
 620      * @return a string representation of this thread info.
 621      */
 622     public String toString() {
 623         StringBuilder sb = new StringBuilder("\"" + getThreadName() + "\"" +
 624                                              (daemon ? " daemon" : "") +
 625                                              " prio=" + priority +
 626                                              " Id=" + getThreadId() + " " +
 627                                              getThreadState());
 628         if (getLockName() != null) {
 629             sb.append(" on " + getLockName());
 630         }
 631         if (getLockOwnerName() != null) {
 632             sb.append(" owned by \"" + getLockOwnerName() +
 633                       "\" Id=" + getLockOwnerId());
 634         }
 635         if (isSuspended()) {
 636             sb.append(" (suspended)");
 637         }
 638         if (isInNative()) {
 639             sb.append(" (in native)");
 640         }
 641         sb.append('\n');
 642         int i = 0;
 643         for (; i < stackTrace.length && i < MAX_FRAMES; i++) {
 644             StackTraceElement ste = stackTrace[i];
 645             sb.append("\tat " + ste.toString());
 646             sb.append('\n');
 647             if (i == 0 && getLockInfo() != null) {
 648                 Thread.State ts = getThreadState();
 649                 switch (ts) {
 650                     case BLOCKED:
 651                         sb.append("\t-  blocked on " + getLockInfo());
 652                         sb.append('\n');
 653                         break;
 654                     case WAITING:
 655                         sb.append("\t-  waiting on " + getLockInfo());
 656                         sb.append('\n');
 657                         break;
 658                     case TIMED_WAITING:
 659                         sb.append("\t-  waiting on " + getLockInfo());
 660                         sb.append('\n');
 661                         break;
 662                     default:
 663                 }
 664             }
 665 
 666             for (MonitorInfo mi : lockedMonitors) {
 667                 if (mi.getLockedStackDepth() == i) {
 668                     sb.append("\t-  locked " + mi);
 669                     sb.append('\n');
 670                 }
 671             }
 672        }
 673        if (i < stackTrace.length) {
 674            sb.append("\t...");
 675            sb.append('\n');
 676        }
 677 
 678        LockInfo[] locks = getLockedSynchronizers();
 679        if (locks.length > 0) {
 680            sb.append("\n\tNumber of locked synchronizers = " + locks.length);
 681            sb.append('\n');
 682            for (LockInfo li : locks) {
 683                sb.append("\t- " + li);
 684                sb.append('\n');
 685            }
 686        }
 687        sb.append('\n');
 688        return sb.toString();
 689     }
 690     private static final int MAX_FRAMES = 8;
 691 
 692     /**
 693      * Returns a {@code ThreadInfo} object represented by the
 694      * given {@code CompositeData}.
 695      * The given {@code CompositeData} must contain the following attributes
 696      * unless otherwise specified below:
 697      * <blockquote>
 698      * <table border summary="The attributes and their types the given CompositeData contains">
 699      * <tr>
 700      *   <th align=left>Attribute Name</th>
 701      *   <th align=left>Type</th>
 702      * </tr>
 703      * <tr>
 704      *   <td>threadId</td>
 705      *   <td>{@code java.lang.Long}</td>
 706      * </tr>
 707      * <tr>
 708      *   <td>threadName</td>
 709      *   <td>{@code java.lang.String}</td>
 710      * </tr>
 711      * <tr>
 712      *   <td>threadState</td>
 713      *   <td>{@code java.lang.String}</td>
 714      * </tr>
 715      * <tr>
 716      *   <td>suspended</td>
 717      *   <td>{@code java.lang.Boolean}</td>
 718      * </tr>
 719      * <tr>
 720      *   <td>inNative</td>
 721      *   <td>{@code java.lang.Boolean}</td>
 722      * </tr>
 723      * <tr>
 724      *   <td>blockedCount</td>
 725      *   <td>{@code java.lang.Long}</td>
 726      * </tr>
 727      * <tr>
 728      *   <td>blockedTime</td>
 729      *   <td>{@code java.lang.Long}</td>
 730      * </tr>
 731      * <tr>
 732      *   <td>waitedCount</td>
 733      *   <td>{@code java.lang.Long}</td>
 734      * </tr>
 735      * <tr>
 736      *   <td>waitedTime</td>
 737      *   <td>{@code java.lang.Long}</td>
 738      * </tr>
 739      * <tr>
 740      *   <td>lockInfo</td>
 741      *   <td>{@code javax.management.openmbean.CompositeData}
 742      *       - the mapped type for {@link LockInfo} as specified in the
 743      *         {@link LockInfo#from} method.
 744      *       <p>
 745      *       If {@code cd} does not contain this attribute,
 746      *       the {@code LockInfo} object will be constructed from
 747      *       the value of the {@code lockName} attribute. </td>
 748      * </tr>
 749      * <tr>
 750      *   <td>lockName</td>
 751      *   <td>{@code java.lang.String}</td>
 752      * </tr>
 753      * <tr>
 754      *   <td>lockOwnerId</td>
 755      *   <td>{@code java.lang.Long}</td>
 756      * </tr>
 757      * <tr>
 758      *   <td>lockOwnerName</td>
 759      *   <td>{@code java.lang.String}</td>
 760      * </tr>
 761      * <tr>
 762      *   <td><a name="StackTrace">stackTrace</a></td>
 763      *   <td>{@code javax.management.openmbean.CompositeData[]}
 764      *       <p>
 765      *       Each element is a {@code CompositeData} representing
 766      *       StackTraceElement containing the following attributes:
 767      *       <blockquote>
 768      *       <table cellspacing=1 cellpadding=0 summary="The attributes and their types the given CompositeData contains">
 769      *       <tr>
 770      *         <th align=left>Attribute Name</th>
 771      *         <th align=left>Type</th>
 772      *       </tr>
 773      *       <tr>
 774      *         <td>className</td>
 775      *         <td>{@code java.lang.String}</td>
 776      *       </tr>
 777      *       <tr>
 778      *         <td>methodName</td>
 779      *         <td>{@code java.lang.String}</td>
 780      *       </tr>
 781      *       <tr>
 782      *         <td>fileName</td>
 783      *         <td>{@code java.lang.String}</td>
 784      *       </tr>
 785      *       <tr>
 786      *         <td>lineNumber</td>
 787      *         <td>{@code java.lang.Integer}</td>
 788      *       </tr>
 789      *       <tr>
 790      *         <td>nativeMethod</td>
 791      *         <td>{@code java.lang.Boolean}</td>
 792      *       </tr>
 793      *       </table>
 794      *       </blockquote>
 795      *   </td>
 796      * </tr>
 797      * <tr>
 798      *   <td>lockedMonitors</td>
 799      *   <td>{@code javax.management.openmbean.CompositeData[]}
 800      *       whose element type is the mapped type for
 801      *       {@link MonitorInfo} as specified in the
 802      *       {@link MonitorInfo#from Monitor.from} method.
 803      *       <p>
 804      *       If {@code cd} does not contain this attribute,
 805      *       this attribute will be set to an empty array. </td>
 806      * </tr>
 807      * <tr>
 808      *   <td>lockedSynchronizers</td>
 809      *   <td>{@code javax.management.openmbean.CompositeData[]}
 810      *       whose element type is the mapped type for
 811      *       {@link LockInfo} as specified in the {@link LockInfo#from} method.
 812      *       <p>
 813      *       If {@code cd} does not contain this attribute,
 814      *       this attribute will be set to an empty array. </td>
 815      * </tr>
 816      * <tr>
 817      *   <td>daemon</td>
 818      *   <td>{@code java.lang.Boolean}</td>
 819      * </tr>
 820      * <tr>
 821      *   <td>priority</td>
 822      *   <td>{@code java.lang.Integer}</td>
 823      * </tr>
 824      * </table>
 825      * </blockquote>
 826      *
 827      * @param cd {@code CompositeData} representing a {@code ThreadInfo}
 828      *
 829      * @throws IllegalArgumentException if {@code cd} does not
 830      *   represent a {@code ThreadInfo} with the attributes described
 831      *   above.
 832      *
 833      * @return a {@code ThreadInfo} object represented
 834      *         by {@code cd} if {@code cd} is not {@code null};
 835      *         {@code null} otherwise.
 836      */
 837     public static ThreadInfo from(CompositeData cd) {
 838         if (cd == null) {
 839             return null;
 840         }
 841 
 842         if (cd instanceof ThreadInfoCompositeData) {
 843             return ((ThreadInfoCompositeData) cd).getThreadInfo();
 844         } else {
 845             return new ThreadInfo(cd);
 846         }
 847     }
 848 
 849     /**
 850      * Returns an array of {@link MonitorInfo} objects, each of which
 851      * represents an object monitor currently locked by the thread
 852      * associated with this {@code ThreadInfo}.
 853      * If no locked monitor was requested for this thread info or
 854      * no monitor is locked by the thread, this method
 855      * will return a zero-length array.
 856      *
 857      * @return an array of {@code MonitorInfo} objects representing
 858      *         the object monitors locked by the thread.
 859      *
 860      * @since 1.6
 861      */
 862     public MonitorInfo[] getLockedMonitors() {
 863         return lockedMonitors;
 864     }
 865 
 866     /**
 867      * Returns an array of {@link LockInfo} objects, each of which
 868      * represents an <a href="LockInfo.html#OwnableSynchronizer">ownable
 869      * synchronizer</a> currently locked by the thread associated with
 870      * this {@code ThreadInfo}.  If no locked synchronizer was
 871      * requested for this thread info or no synchronizer is locked by
 872      * the thread, this method will return a zero-length array.
 873      *
 874      * @return an array of {@code LockInfo} objects representing
 875      *         the ownable synchronizers locked by the thread.
 876      *
 877      * @since 1.6
 878      */
 879     public LockInfo[] getLockedSynchronizers() {
 880         return lockedSynchronizers;
 881     }
 882 
 883     private static final StackTraceElement[] NO_STACK_TRACE =
 884         new StackTraceElement[0];
 885 }