Frames | No Frames |
1: /* ThreadInfo.java - Information on a thread 2: Copyright (C) 2006 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package java.lang.management; 39: 40: import java.util.Arrays; 41: 42: import javax.management.openmbean.ArrayType; 43: import javax.management.openmbean.CompositeData; 44: import javax.management.openmbean.CompositeType; 45: import javax.management.openmbean.OpenDataException; 46: import javax.management.openmbean.OpenType; 47: import javax.management.openmbean.SimpleType; 48: 49: /** 50: * <p> 51: * A class which maintains information about a particular 52: * thread. This information includes: 53: * </p> 54: * <ul> 55: * <li><strong>General Thread Information:</strong> 56: * <ul> 57: * <li>The identifier of the thread.</li> 58: * <li>The name of the thread.</li> 59: * </ul> 60: * </li> 61: * <li><strong>Execution Information:</strong> 62: * <ul> 63: * <li>The current state of the thread (e.g. blocked, runnable)</li> 64: * <li>The object upon which the thread is blocked, either because 65: * the thread is waiting to obtain the monitor of that object to enter 66: * one of its synchronized monitor, or because 67: * {@link java.lang.Object#wait()} has been called while the thread 68: * was within a method of that object.</li> 69: * <li>The thread identifier of the current thread holding an object's 70: * monitor, upon which the thread described here is blocked.</li> 71: * <li>The stack trace of the thread (if requested on creation 72: * of this object</li> 73: * <li>The current locks held on object monitors by the thread.</li> 74: * <li>The current locks held on ownable synchronizers by the thread.</li> 75: * </ul> 76: * <li><strong>Synchronization Statistics</strong> 77: * <ul> 78: * <li>The number of times the thread has been blocked waiting for 79: * an object's monitor or in a {@link java.lang.Object#wait()} call.</li> 80: * <li>The accumulated time the thread has been blocked waiting for 81: * an object's monitor on in a {@link java.lang.Object#wait()} call. 82: * The availability of these statistics depends on the virtual machine's 83: * support for thread contention monitoring (see 84: * {@link ThreadMXBean#isThreadContentionMonitoringSupported()}.</li> 85: * </ul> 86: * </li> 87: * </ul> 88: * 89: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 90: * @since 1.5 91: * @see ThreadMXBean#isThreadContentionMonitoringSupported() 92: */ 93: public class ThreadInfo 94: { 95: 96: /** 97: * The id of the thread which this instance concerns. 98: */ 99: 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: }