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 ≤ <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 ≤ <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