001 /* ThreadInfo.java - Information on a thread 002 Copyright (C) 2006 Free Software Foundation 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package java.lang.management; 039 040 import java.util.Arrays; 041 042 import javax.management.openmbean.ArrayType; 043 import javax.management.openmbean.CompositeData; 044 import javax.management.openmbean.CompositeType; 045 import javax.management.openmbean.OpenDataException; 046 import javax.management.openmbean.OpenType; 047 import javax.management.openmbean.SimpleType; 048 049 /** 050 * <p> 051 * A class which maintains information about a particular 052 * thread. This information includes: 053 * </p> 054 * <ul> 055 * <li><strong>General Thread Information:</strong> 056 * <ul> 057 * <li>The identifier of the thread.</li> 058 * <li>The name of the thread.</li> 059 * </ul> 060 * </li> 061 * <li><strong>Execution Information:</strong> 062 * <ul> 063 * <li>The current state of the thread (e.g. blocked, runnable)</li> 064 * <li>The object upon which the thread is blocked, either because 065 * the thread is waiting to obtain the monitor of that object to enter 066 * one of its synchronized monitor, or because 067 * {@link java.lang.Object#wait()} has been called while the thread 068 * was within a method of that object.</li> 069 * <li>The thread identifier of the current thread holding an object's 070 * monitor, upon which the thread described here is blocked.</li> 071 * <li>The stack trace of the thread (if requested on creation 072 * of this object</li> 073 * <li>The current locks held on object monitors by the thread.</li> 074 * <li>The current locks held on ownable synchronizers by the thread.</li> 075 * </ul> 076 * <li><strong>Synchronization Statistics</strong> 077 * <ul> 078 * <li>The number of times the thread has been blocked waiting for 079 * an object's monitor or in a {@link java.lang.Object#wait()} call.</li> 080 * <li>The accumulated time the thread has been blocked waiting for 081 * an object's monitor on in a {@link java.lang.Object#wait()} call. 082 * The availability of these statistics depends on the virtual machine's 083 * support for thread contention monitoring (see 084 * {@link ThreadMXBean#isThreadContentionMonitoringSupported()}.</li> 085 * </ul> 086 * </li> 087 * </ul> 088 * 089 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 090 * @since 1.5 091 * @see ThreadMXBean#isThreadContentionMonitoringSupported() 092 */ 093 public class ThreadInfo 094 { 095 096 /** 097 * The id of the thread which this instance concerns. 098 */ 099 private long threadId; 100 101 /** 102 * The name of the thread which this instance concerns. 103 */ 104 private String threadName; 105 106 /** 107 * The state of the thread which this instance concerns. 108 */ 109 private Thread.State threadState; 110 111 /** 112 * The number of times the thread has been blocked. 113 */ 114 private long blockedCount; 115 116 /** 117 * The accumulated number of milliseconds the thread has 118 * been blocked (used only with thread contention monitoring 119 * support). 120 */ 121 private long blockedTime; 122 123 /** 124 * The name of the monitor lock on which this thread 125 * is blocked (if any). 126 */ 127 private String lockName; 128 129 /** 130 * The id of the thread which owns the monitor lock on 131 * which this thread is blocked, or <code>-1</code> 132 * if there is no owner. 133 */ 134 private long lockOwnerId; 135 136 /** 137 * The name of the thread which owns the monitor lock on 138 * which this thread is blocked, or <code>null</code> 139 * if there is no owner. 140 */ 141 private String lockOwnerName; 142 143 /** 144 * The number of times the thread has been in a waiting 145 * state. 146 */ 147 private long waitedCount; 148 149 /** 150 * The accumulated number of milliseconds the thread has 151 * been waiting (used only with thread contention monitoring 152 * support). 153 */ 154 private long waitedTime; 155 156 /** 157 * True if the thread is in a native method. 158 */ 159 private boolean isInNative; 160 161 /** 162 * True if the thread is suspended. 163 */ 164 private boolean isSuspended; 165 166 /** 167 * The stack trace of the thread. 168 */ 169 private StackTraceElement[] trace; 170 171 /** 172 * The array of information on monitors locked by the thread. 173 */ 174 private MonitorInfo[] lockedMonitors; 175 176 /** 177 * The array of information on ownable synchronizers locked 178 * by the thread. 179 */ 180 private LockInfo[] lockedSynchronizers; 181 182 /** 183 * Cache a local reference to the thread management bean. 184 */ 185 private static ThreadMXBean bean = null; 186 187 /** 188 * Cache the {@link javax.management.openmbean.CompositeType} 189 * for the {@link StackTraceElement}. 190 */ 191 private static CompositeType seType; 192 193 /** 194 * Constructs a new {@link ThreadInfo} corresponding 195 * to the thread details specified. 196 * 197 * @param threadId the id of the thread on which this 198 * new instance will be based. 199 * @param threadName the name of the thread on which 200 * this new instance will be based. 201 * @param threadState the state of the thread on which 202 * this new instance will be based. 203 * @param blockedCount the number of times the thread 204 * has been blocked. 205 * @param blockedTime the accumulated number of milliseconds 206 * the specified thread has been blocked 207 * (only used with contention monitoring enabled) 208 * @param lockName the name of the monitor lock the thread is waiting for 209 * (only used if blocked) 210 * @param lockOwnerId the id of the thread which owns the monitor 211 * lock, or <code>-1</code> if it doesn't have an owner 212 * (only used if blocked) 213 * @param lockOwnerName the name of the thread which owns the monitor 214 * lock, or <code>null</code> if it doesn't have an 215 * owner (only used if blocked) 216 * @param waitedCount the number of times the thread has been in a 217 * waiting state. 218 * @param waitedTime the accumulated number of milliseconds the 219 * specified thread has been waiting 220 * (only used with contention monitoring enabled) 221 * @param isInNative true if the thread is in a native method. 222 * @param isSuspended true if the thread is suspended. 223 * @param trace the stack trace of the thread to a pre-determined 224 * depth (see VMThreadMXBeanImpl) 225 * @param lockedMonitors an array of {@link MonitorInfo} objects 226 * representing locks held on object monitors 227 * by the thread. 228 * @param lockedSynchronizers an array of {@link LockInfo} objects 229 * representing locks held on ownable 230 * synchronizers by the thread. 231 * 232 * @since 1.6 233 */ 234 private ThreadInfo(long threadId, String threadName, Thread.State threadState, 235 long blockedCount, long blockedTime, String lockName, 236 long lockOwnerId, String lockOwnerName, long waitedCount, 237 long waitedTime, boolean isInNative, boolean isSuspended, 238 StackTraceElement[] trace, MonitorInfo[] lockedMonitors, 239 LockInfo[] lockedSynchronizers) 240 { 241 this.threadId = threadId; 242 this.threadName = threadName; 243 this.threadState = threadState; 244 this.blockedCount = blockedCount; 245 this.blockedTime = blockedTime; 246 this.lockName = lockName; 247 this.lockOwnerId = lockOwnerId; 248 this.lockOwnerName = lockOwnerName; 249 this.waitedCount = waitedCount; 250 this.waitedTime = waitedTime; 251 this.isInNative = isInNative; 252 this.isSuspended = isSuspended; 253 this.trace = trace; 254 this.lockedMonitors = lockedMonitors; 255 this.lockedSynchronizers = lockedSynchronizers; 256 } 257 258 /** 259 * Checks for an attribute in a {@link CompositeData} structure 260 * with the correct type. 261 * 262 * @param ctype the composite data type to check. 263 * @param name the name of the attribute. 264 * @param type the type to check for. 265 * @throws IllegalArgumentException if the attribute is absent 266 * or of the wrong type. 267 */ 268 static void checkAttribute(CompositeType ctype, String name, 269 OpenType type) 270 throws IllegalArgumentException 271 { 272 OpenType foundType = ctype.getType(name); 273 if (foundType == null) 274 throw new IllegalArgumentException("Could not find a field named " + 275 name); 276 if (!(foundType.equals(type))) 277 throw new IllegalArgumentException("Field " + name + " is not of " + 278 "type " + type.getClassName()); 279 } 280 281 /** 282 * Returns the {@link javax.management.openmbean.CompositeType} for 283 * a {@link StackTraceElement}. 284 * 285 * @return the type for the stack trace element. 286 */ 287 static CompositeType getStackTraceType() 288 { 289 if (seType == null) 290 try 291 { 292 seType = new CompositeType(StackTraceElement.class.getName(), 293 "An element of a stack trace", 294 new String[] { "className", "methodName", 295 "fileName", "lineNumber", 296 "nativeMethod" 297 }, 298 new String[] { "Name of the class", 299 "Name of the method", 300 "Name of the source code file", 301 "Line number", 302 "True if this is a native method" 303 }, 304 new OpenType[] { 305 SimpleType.STRING, SimpleType.STRING, 306 SimpleType.STRING, SimpleType.INTEGER, 307 SimpleType.BOOLEAN 308 }); 309 } 310 catch (OpenDataException e) 311 { 312 throw new IllegalStateException("Something went wrong in creating " + 313 "the composite data type for the " + 314 "stack trace element.", e); 315 } 316 return seType; 317 } 318 319 /** 320 * <p> 321 * Returns a {@link ThreadInfo} instance using the values 322 * given in the supplied 323 * {@link javax.management.openmbean.CompositeData} object. 324 * The composite data instance should contain the following 325 * attributes with the specified types: 326 * </p> 327 * <table> 328 * <th><td>Name</td><td>Type</td></th> 329 * <tr><td>threadId</td><td>java.lang.Long</td></tr> 330 * <tr><td>threadName</td><td>java.lang.String</td></tr> 331 * <tr><td>threadState</td><td>java.lang.String</td></tr> 332 * <tr><td>suspended</td><td>java.lang.Boolean</td></tr> 333 * <tr><td>inNative</td><td>java.lang.Boolean</td></tr> 334 * <tr><td>blockedCount</td><td>java.lang.Long</td></tr> 335 * <tr><td>blockedTime</td><td>java.lang.Long</td></tr> 336 * <tr><td>waitedCount</td><td>java.lang.Long</td></tr> 337 * <tr><td>waitedTime</td><td>java.lang.Long</td></tr> 338 * <tr><td>lockName</td><td>java.lang.String</td></tr> 339 * <tr><td>lockOwnerId</td><td>java.lang.Long</td></tr> 340 * <tr><td>lockOwnerName</td><td>java.lang.String</td></tr> 341 * <tr><td>stackTrace</td><td>javax.management.openmbean.CompositeData[] 342 * </td></tr> 343 * </table> 344 * <p> 345 * The stack trace is further described as: 346 * </p> 347 * <table> 348 * <th><td>Name</td><td>Type</td></th> 349 * <tr><td>className</td><td>java.lang.String</td></tr> 350 * <tr><td>methodName</td><td>java.lang.String</td></tr> 351 * <tr><td>fileName</td><td>java.lang.String</td></tr> 352 * <tr><td>lineNumber</td><td>java.lang.Integer</td></tr> 353 * <tr><td>nativeMethod</td><td>java.lang.Boolean</td></tr> 354 * </table> 355 * 356 * @param data the composite data structure to take values from. 357 * @return a new instance containing the values from the 358 * composite data structure, or <code>null</code> 359 * if the data structure was also <code>null</code>. 360 * @throws IllegalArgumentException if the composite data structure 361 * does not match the structure 362 * outlined above. 363 */ 364 public static ThreadInfo from(CompositeData data) 365 { 366 if (data == null) 367 return null; 368 CompositeType type = data.getCompositeType(); 369 checkAttribute(type, "ThreadId", SimpleType.LONG); 370 checkAttribute(type, "ThreadName", SimpleType.STRING); 371 checkAttribute(type, "ThreadState", SimpleType.STRING); 372 checkAttribute(type, "Suspended", SimpleType.BOOLEAN); 373 checkAttribute(type, "InNative", SimpleType.BOOLEAN); 374 checkAttribute(type, "BlockedCount", SimpleType.LONG); 375 checkAttribute(type, "BlockedTime", SimpleType.LONG); 376 checkAttribute(type, "WaitedCount", SimpleType.LONG); 377 checkAttribute(type, "WaitedTime", SimpleType.LONG); 378 checkAttribute(type, "LockName", SimpleType.STRING); 379 checkAttribute(type, "LockOwnerId", SimpleType.LONG); 380 checkAttribute(type, "LockOwnerName", SimpleType.STRING); 381 try 382 { 383 checkAttribute(type, "StackTrace", 384 new ArrayType(1, getStackTraceType())); 385 } 386 catch (OpenDataException e) 387 { 388 throw new IllegalStateException("Something went wrong in creating " + 389 "the array for the stack trace element.", 390 e); 391 } 392 OpenType foundType = type.getType("LockedMonitors"); 393 if (foundType != null) 394 try 395 { 396 CompositeType mType = new CompositeType(MonitorInfo.class.getName(), 397 "Information on a object monitor lock", 398 new String[] { "ClassName", 399 "IdentityHashCode", 400 "LockedStackDepth", 401 "LockedStackFrame" 402 }, 403 new String[] { "Name of the class", 404 "Identity hash code " + 405 "of the class", 406 "Stack depth at time " + 407 "of lock", 408 "Stack frame at time " + 409 "of lock", 410 }, 411 new OpenType[] { 412 SimpleType.STRING, SimpleType.INTEGER, 413 SimpleType.INTEGER, getStackTraceType() 414 }); 415 if (!(foundType.equals(new ArrayType(1, mType)))) 416 throw new IllegalArgumentException("Field LockedMonitors is not of " + 417 "type " + mType.getClassName()); 418 } 419 catch (OpenDataException e) 420 { 421 throw new IllegalStateException("Something went wrong in creating " + 422 "the composite data type for the " + 423 "object monitor information array.", e); 424 } 425 foundType = type.getType("LockedSynchronizers"); 426 if (foundType != null) 427 try 428 { 429 CompositeType lType = new CompositeType(LockInfo.class.getName(), 430 "Information on a lock", 431 new String[] { "ClassName", 432 "IdentityHashCode" 433 }, 434 new String[] { "Name of the class", 435 "Identity hash code " + 436 "of the class" 437 }, 438 new OpenType[] { 439 SimpleType.STRING, SimpleType.INTEGER 440 }); 441 if (!(foundType.equals(new ArrayType(1, lType)))) 442 throw new IllegalArgumentException("Field LockedSynchronizers is not of " + 443 "type " + lType.getClassName()); 444 } 445 catch (OpenDataException e) 446 { 447 throw new IllegalStateException("Something went wrong in creating " + 448 "the composite data type for the " + 449 "ownable synchronizerinformation array.", e); 450 } 451 CompositeData[] dTraces = (CompositeData[]) data.get("StackTrace"); 452 StackTraceElement[] traces = new StackTraceElement[dTraces.length]; 453 for (int a = 0; a < dTraces.length; ++a) 454 /* FIXME: We can't use the boolean as there is no available 455 constructor. */ 456 traces[a] = 457 new StackTraceElement((String) dTraces[a].get("ClassName"), 458 (String) dTraces[a].get("MethodName"), 459 (String) dTraces[a].get("FileName"), 460 ((Integer) 461 dTraces[a].get("LineNumber")).intValue()); 462 MonitorInfo[] mInfo; 463 if (data.containsKey("LockedMonitors")) 464 { 465 CompositeData[] dmInfos = (CompositeData[]) data.get("LockedMonitors"); 466 mInfo = new MonitorInfo[dmInfos.length]; 467 for (int a = 0; a < dmInfos.length; ++a) 468 mInfo[a] = MonitorInfo.from(dmInfos[a]); 469 } 470 else 471 mInfo = new MonitorInfo[]{}; 472 LockInfo[] lInfo; 473 if (data.containsKey("LockedSynchronizers")) 474 { 475 CompositeData[] dlInfos = (CompositeData[]) data.get("LockedSynchronizers"); 476 lInfo = new LockInfo[dlInfos.length]; 477 for (int a = 0; a < dlInfos.length; ++a) 478 lInfo[a] = new LockInfo((String) dlInfos[a].get("ClassName"), 479 (Integer) dlInfos[a].get("IdentityHashCode")); 480 } 481 else 482 lInfo = new LockInfo[]{}; 483 return new ThreadInfo(((Long) data.get("ThreadId")).longValue(), 484 (String) data.get("ThreadName"), 485 Thread.State.valueOf((String) data.get("ThreadState")), 486 ((Long) data.get("BlockedCount")).longValue(), 487 ((Long) data.get("BlockedTime")).longValue(), 488 (String) data.get("LockName"), 489 ((Long) data.get("LockOwnerId")).longValue(), 490 (String) data.get("LockOwnerName"), 491 ((Long) data.get("WaitedCount")).longValue(), 492 ((Long) data.get("WaitedTime")).longValue(), 493 ((Boolean) data.get("InNative")).booleanValue(), 494 ((Boolean) data.get("Suspended")).booleanValue(), 495 traces, mInfo, lInfo); 496 } 497 498 /** 499 * Returns the number of times this thread has been 500 * in the {@link java.lang.Thread.State#BLOCKED} state. 501 * A thread enters this state when it is waiting to 502 * obtain an object's monitor. This may occur either 503 * on entering a synchronized method for the first time, 504 * or on re-entering it following a call to 505 * {@link java.lang.Object#wait()}. 506 * 507 * @return the number of times this thread has been blocked. 508 */ 509 public long getBlockedCount() 510 { 511 return blockedCount; 512 } 513 514 /** 515 * <p> 516 * Returns the accumulated number of milliseconds this 517 * thread has been in the 518 * {@link java.lang.Thread.State#BLOCKED} state 519 * since thread contention monitoring was last enabled. 520 * A thread enters this state when it is waiting to 521 * obtain an object's monitor. This may occur either 522 * on entering a synchronized method for the first time, 523 * or on re-entering it following a call to 524 * {@link java.lang.Object#wait()}. 525 * </p> 526 * <p> 527 * Use of this method requires virtual machine support 528 * for thread contention monitoring and for this support 529 * to be enabled. 530 * </p> 531 * 532 * @return the accumulated time (in milliseconds) that this 533 * thread has spent in the blocked state, since 534 * thread contention monitoring was enabled, or -1 535 * if thread contention monitoring is disabled. 536 * @throws UnsupportedOperationException if the virtual 537 * machine does not 538 * support contention 539 * monitoring. 540 * @see ThreadMXBean#isThreadContentionMonitoringEnabled() 541 * @see ThreadMXBean#isThreadContentionMonitoringSupported() 542 */ 543 public long getBlockedTime() 544 { 545 if (bean == null) 546 bean = ManagementFactory.getThreadMXBean(); 547 // Will throw UnsupportedOperationException for us 548 if (bean.isThreadContentionMonitoringEnabled()) 549 return blockedTime; 550 else 551 return -1; 552 } 553 554 /** 555 * Returns an array of {@link MonitorInfo} objects representing 556 * information on the locks on object monitors held by the thread. 557 * If no locks are held, or such information was not requested 558 * on creating this {@link ThreadInfo} object, a zero-length 559 * array will be returned. 560 * 561 * @return information on object monitors locked by this thread. 562 */ 563 public MonitorInfo[] getLockedMonitors() 564 { 565 return lockedMonitors; 566 } 567 568 /** 569 * Returns an array of {@link LockInfo} objects representing 570 * information on the locks on ownable synchronizers held by the thread. 571 * If no locks are held, or such information was not requested 572 * on creating this {@link ThreadInfo} object, a zero-length 573 * array will be returned. 574 * 575 * @return information on ownable synchronizers locked by this thread. 576 */ 577 public LockInfo[] getLockedSynchronizers() 578 { 579 return lockedSynchronizers; 580 } 581 582 /** 583 * <p> 584 * Returns a {@link LockInfo} object representing the 585 * lock on which this thread is blocked. If the thread 586 * is not blocked, this method returns <code>null</code>. 587 * </p> 588 * <p> 589 * The thread may be blocked due to one of three reasons: 590 * </p> 591 * <ol> 592 * <li>The thread is in the <code>BLOCKED</code> state 593 * waiting to acquire an object monitor in order to enter 594 * a synchronized method or block.</li> 595 * <li>The thread is in the <code>WAITING</code> or 596 * <code>TIMED_WAITING</code> state due to a call to 597 * {@link java.lang.Object#wait()}.</li> 598 * <li>The thread is in the <code>WAITING</code> or 599 * <code>TIMED_WAITING</code> state due to a call 600 * to {@link java.util.concurrent.locks.LockSupport#park()}. 601 * The lock is the return value of 602 * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> 603 * </ol> 604 * 605 * @return a {@link LockInfo} object representing the lock on 606 * which the thread is blocked, or <code>null</code> if 607 * the thread isn't blocked. 608 * @since 1.6 609 * @see #getLockName() 610 */ 611 public LockInfo getLockInfo() 612 { 613 String lockName = getLockName(); 614 int at = lockName.indexOf('@'); 615 return new LockInfo(lockName.substring(0, at), 616 Integer.decode(lockName.substring(at + 1))); 617 } 618 619 /** 620 * <p> 621 * Returns a {@link java.lang.String} representation of 622 * the lock on which this thread is blocked. If 623 * the thread is not blocked, this method returns 624 * <code>null</code>. 625 * </p> 626 * <p> 627 * The returned {@link java.lang.String} is constructed 628 * using the class name and identity hashcode (usually 629 * the memory address of the object) of the lock. The 630 * two are separated by the '@' character, and the identity 631 * hashcode is represented in hexadecimal. Thus, for a 632 * lock, <code>l</code>, the returned value is 633 * the result of concatenating 634 * <code>l.getClass().getName()</code>, <code>"@"</code> 635 * and 636 * <code>Integer.toHexString(System.identityHashCode(l))</code>. 637 * The value is only unique to the extent that the identity 638 * hash code is also unique. The value is the same as would 639 * be returned by <code>getLockInfo().toString()</code> 640 * </p> 641 * 642 * @return a string representing the lock on which this 643 * thread is blocked, or <code>null</code> if 644 * the thread is not blocked. 645 */ 646 public String getLockName() 647 { 648 if (!isThreadBlocked()) 649 return null; 650 return lockName; 651 } 652 653 /** 654 * Returns the identifier of the thread which owns the 655 * monitor lock this thread is waiting for. -1 is returned 656 * if either this thread is not blocked, or the lock is 657 * not held by any other thread. 658 * 659 * @return the thread identifier of thread holding the lock 660 * this thread is waiting for, or -1 if the thread 661 * is not blocked or the lock is not held by another 662 * thread. 663 */ 664 public long getLockOwnerId() 665 { 666 if (!isThreadBlocked()) 667 return -1; 668 return lockOwnerId; 669 } 670 671 /** 672 * Returns the name of the thread which owns the 673 * monitor lock this thread is waiting for. <code>null</code> 674 * is returned if either this thread is not blocked, 675 * or the lock is not held by any other thread. 676 * 677 * @return the thread identifier of thread holding the lock 678 * this thread is waiting for, or <code>null</code> 679 * if the thread is not blocked or the lock is not 680 * held by another thread. 681 */ 682 public String getLockOwnerName() 683 { 684 if (!isThreadBlocked()) 685 return null; 686 return lockOwnerName; 687 } 688 689 /** 690 * <p> 691 * Returns the stack trace of this thread to the depth 692 * specified on creation of this {@link ThreadInfo} 693 * object. If the depth is zero, an empty array will 694 * be returned. For non-zero arrays, the elements 695 * start with the most recent trace at position zero. 696 * The bottom of the stack represents the oldest method 697 * invocation which meets the depth requirements. 698 * </p> 699 * <p> 700 * Some virtual machines may not be able to return 701 * stack trace information for a thread. In these 702 * cases, an empty array will also be returned. 703 * </p> 704 * 705 * @return an array of {@link java.lang.StackTraceElement}s 706 * representing the trace of this thread. 707 */ 708 public StackTraceElement[] getStackTrace() 709 { 710 return trace; 711 } 712 713 /** 714 * Returns the identifier of the thread associated with 715 * this instance of {@link ThreadInfo}. 716 * 717 * @return the thread's identifier. 718 */ 719 public long getThreadId() 720 { 721 return threadId; 722 } 723 724 /** 725 * Returns the name of the thread associated with 726 * this instance of {@link ThreadInfo}. 727 * 728 * @return the thread's name. 729 */ 730 public String getThreadName() 731 { 732 return threadName; 733 } 734 735 /** 736 * Returns the state of the thread associated with 737 * this instance of {@link ThreadInfo}. 738 * 739 * @return the thread's state. 740 */ 741 public Thread.State getThreadState() 742 { 743 return threadState; 744 } 745 746 /** 747 * Returns the number of times this thread has been 748 * in the {@link java.lang.Thread.State#WAITING} 749 * or {@link java.lang.Thread.State#TIMED_WAITING} state. 750 * A thread enters one of these states when it is waiting 751 * due to a call to {@link java.lang.Object.wait()}, 752 * {@link java.lang.Object.join()} or 753 * {@link java.lang.concurrent.locks.LockSupport.park()}, 754 * either with an infinite or timed delay, respectively. 755 * 756 * @return the number of times this thread has been waiting. 757 */ 758 public long getWaitedCount() 759 { 760 return waitedCount; 761 } 762 763 /** 764 * <p> 765 * Returns the accumulated number of milliseconds this 766 * thread has been in the 767 * {@link java.lang.Thread.State#WAITING} or 768 * {@link java.lang.Thread.State#TIMED_WAITING} state, 769 * since thread contention monitoring was last enabled. 770 * A thread enters one of these states when it is waiting 771 * due to a call to {@link java.lang.Object.wait()}, 772 * {@link java.lang.Object.join()} or 773 * {@link java.lang.concurrent.locks.LockSupport.park()}, 774 * either with an infinite or timed delay, respectively. 775 * </p> 776 * <p> 777 * Use of this method requires virtual machine support 778 * for thread contention monitoring and for this support 779 * to be enabled. 780 * </p> 781 * 782 * @return the accumulated time (in milliseconds) that this 783 * thread has spent in one of the waiting states, since 784 * thread contention monitoring was enabled, or -1 785 * if thread contention monitoring is disabled. 786 * @throws UnsupportedOperationException if the virtual 787 * machine does not 788 * support contention 789 * monitoring. 790 * @see ThreadMXBean#isThreadContentionMonitoringEnabled() 791 * @see ThreadMXBean#isThreadContentionMonitoringSupported() 792 */ 793 public long getWaitedTime() 794 { 795 if (bean == null) 796 bean = ManagementFactory.getThreadMXBean(); 797 // Will throw UnsupportedOperationException for us 798 if (bean.isThreadContentionMonitoringEnabled()) 799 return waitedTime; 800 else 801 return -1; 802 } 803 804 /** 805 * Returns true if the thread is in a native method. This 806 * excludes native code which forms part of the virtual 807 * machine itself, or which results from Just-In-Time 808 * compilation. 809 * 810 * @return true if the thread is in a native method, false 811 * otherwise. 812 */ 813 public boolean isInNative() 814 { 815 return isInNative; 816 } 817 818 /** 819 * Returns true if the thread has been suspended using 820 * {@link java.lang.Thread#suspend()}. 821 * 822 * @return true if the thread is suspended, false otherwise. 823 */ 824 public boolean isSuspended() 825 { 826 return isSuspended; 827 } 828 829 /** 830 * Returns a {@link java.lang.String} representation of 831 * this {@link ThreadInfo} object. This takes the form 832 * <code>java.lang.management.ThreadInfo[id=tid, name=n, 833 * state=s, blockedCount=bc, waitedCount=wc, isInNative=iin, 834 * isSuspended=is]</code>, where <code>tid</code> is 835 * the thread identifier, <code>n</code> is the 836 * thread name, <code>s</code> is the thread state, 837 * <code>bc</code> is the blocked state count, 838 * <code>wc</code> is the waiting state count and 839 * <code>iin</code> and <code>is</code> are boolean 840 * flags to indicate the thread is in native code or 841 * suspended respectively. If the thread is blocked, 842 * <code>lock=l, lockOwner=lo</code> is also included, 843 * where <code>l</code> is the lock waited for, and 844 * <code>lo</code> is the thread which owns the lock 845 * (or null if there is no owner). 846 * 847 * @return the string specified above. 848 */ 849 public String toString() 850 { 851 return getClass().getName() + 852 "[id=" + threadId + 853 ", name=" + threadName + 854 ", state=" + threadState + 855 ", blockedCount=" + blockedCount + 856 ", waitedCount=" + waitedCount + 857 ", isInNative=" + isInNative + 858 ", isSuspended=" + isSuspended + 859 (isThreadBlocked() ? 860 ", lockOwnerId=" + lockOwnerId + 861 ", lockOwnerName=" + lockOwnerName : "") + 862 ", lockedMonitors=" + Arrays.toString(lockedMonitors) + 863 ", lockedSynchronizers=" + Arrays.toString(lockedSynchronizers) + 864 "]"; 865 } 866 867 /** 868 * <p> 869 * Returns true if the thread is in a blocked state. 870 * The thread is regarded as blocked if: 871 * </p> 872 * <ol> 873 * <li>The thread is in the <code>BLOCKED</code> state 874 * waiting to acquire an object monitor in order to enter 875 * a synchronized method or block.</li> 876 * <li>The thread is in the <code>WAITING</code> or 877 * <code>TIMED_WAITING</code> state due to a call to 878 * {@link java.lang.Object#wait()}.</li> 879 * <li>The thread is in the <code>WAITING</code> or 880 * <code>TIMED_WAITING</code> state due to a call 881 * to {@link java.util.concurrent.locks.LockSupport#park()}. 882 * The lock is the return value of 883 * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> 884 * </ol> 885 * 886 * @return true if the thread is blocked. 887 */ 888 private boolean isThreadBlocked() 889 { 890 return (threadState == Thread.State.BLOCKED || 891 threadState == Thread.State.WAITING || 892 threadState == Thread.State.TIMED_WAITING); 893 } 894 895 }