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 specified. 196 * 197 * @param thread the thread on which the new instance 198 * will be based. 199 * @param blockedCount the number of times the thread 200 * has been blocked. 201 * @param blockedTime the accumulated number of milliseconds 202 * the specified thread has been blocked 203 * (only used with contention monitoring enabled) 204 * @param lock the monitor lock the thread is waiting for 205 * (only used if blocked) 206 * @param lockOwner the thread which owns the monitor lock, or 207 * <code>null</code> if it doesn't have an owner 208 * (only used if blocked) 209 * @param waitedCount the number of times the thread has been in a 210 * waiting state. 211 * @param waitedTime the accumulated number of milliseconds the 212 * specified thread has been waiting 213 * (only used with contention monitoring enabled) 214 * @param isInNative true if the thread is in a native method. 215 * @param isSuspended true if the thread is suspended. 216 * @param trace the stack trace of the thread to a pre-determined 217 * depth (see VMThreadMXBeanImpl) 218 */ 219 private ThreadInfo(Thread thread, long blockedCount, long blockedTime, 220 Object lock, Thread lockOwner, long waitedCount, 221 long waitedTime, boolean isInNative, boolean isSuspended, 222 StackTraceElement[] trace) 223 { 224 this(thread, blockedCount, blockedTime, lock, lockOwner, waitedCount, 225 waitedTime, isInNative, isSuspended, trace, new MonitorInfo[]{}, 226 new LockInfo[]{}); 227 } 228 229 /** 230 * Constructs a new {@link ThreadInfo} corresponding 231 * to the thread specified. 232 * 233 * @param thread the thread on which the new instance 234 * will be based. 235 * @param blockedCount the number of times the thread 236 * has been blocked. 237 * @param blockedTime the accumulated number of milliseconds 238 * the specified thread has been blocked 239 * (only used with contention monitoring enabled) 240 * @param lock the monitor lock the thread is waiting for 241 * (only used if blocked) 242 * @param lockOwner the thread which owns the monitor lock, or 243 * <code>null</code> if it doesn't have an owner 244 * (only used if blocked) 245 * @param waitedCount the number of times the thread has been in a 246 * waiting state. 247 * @param waitedTime the accumulated number of milliseconds the 248 * specified thread has been waiting 249 * (only used with contention monitoring enabled) 250 * @param isInNative true if the thread is in a native method. 251 * @param isSuspended true if the thread is suspended. 252 * @param trace the stack trace of the thread to a pre-determined 253 * depth (see VMThreadMXBeanImpl) 254 * @param lockedMonitors an array of {@link MonitorInfo} objects 255 * representing locks held on object monitors 256 * by the thread. 257 * @param lockedSynchronizers an array of {@link LockInfo} objects 258 * representing locks held on ownable 259 * synchronizers by the thread. 260 * @since 1.6 261 */ 262 private ThreadInfo(Thread thread, long blockedCount, long blockedTime, 263 Object lock, Thread lockOwner, long waitedCount, 264 long waitedTime, boolean isInNative, boolean isSuspended, 265 StackTraceElement[] trace, MonitorInfo[] lockedMonitors, 266 LockInfo[] lockedSynchronizers) 267 { 268 this(thread.getId(), thread.getName(), thread.getState(), blockedCount, blockedTime, 269 lock == null ? null : lock.getClass().getName() + "@" + 270 Integer.toHexString(System.identityHashCode(lock)), 271 lockOwner == null ? -1 : lockOwner.getId(), 272 lockOwner == null ? null : lockOwner.getName(), 273 waitedCount, waitedTime, isInNative, isSuspended, 274 trace, lockedMonitors, lockedSynchronizers); 275 } 276 277 /** 278 * Constructs a new {@link ThreadInfo} corresponding 279 * to the thread details specified. 280 * 281 * @param threadId the id of the thread on which this 282 * new instance will be based. 283 * @param threadName the name of the thread on which 284 * this new instance will be based. 285 * @param threadState the state of the thread on which 286 * this new instance will be based. 287 * @param blockedCount the number of times the thread 288 * has been blocked. 289 * @param blockedTime the accumulated number of milliseconds 290 * the specified thread has been blocked 291 * (only used with contention monitoring enabled) 292 * @param lockName the name of the monitor lock the thread is waiting for 293 * (only used if blocked) 294 * @param lockOwnerId the id of the thread which owns the monitor 295 * lock, or <code>-1</code> if it doesn't have an owner 296 * (only used if blocked) 297 * @param lockOwnerName the name of the thread which owns the monitor 298 * lock, or <code>null</code> if it doesn't have an 299 * owner (only used if blocked) 300 * @param waitedCount the number of times the thread has been in a 301 * waiting state. 302 * @param waitedTime the accumulated number of milliseconds the 303 * specified thread has been waiting 304 * (only used with contention monitoring enabled) 305 * @param isInNative true if the thread is in a native method. 306 * @param isSuspended true if the thread is suspended. 307 * @param trace the stack trace of the thread to a pre-determined 308 * depth (see VMThreadMXBeanImpl) 309 */ 310 private ThreadInfo(long threadId, String threadName, Thread.State threadState, 311 long blockedCount, long blockedTime, String lockName, 312 long lockOwnerId, String lockOwnerName, long waitedCount, 313 long waitedTime, boolean isInNative, boolean isSuspended, 314 StackTraceElement[] trace) 315 { 316 this(threadId, threadName, threadState, blockedCount, blockedTime, 317 lockName, lockOwnerId, lockOwnerName, waitedCount, waitedTime, 318 isInNative, isSuspended, trace, new MonitorInfo[]{}, new LockInfo[]{}); 319 } 320 321 /** 322 * Constructs a new {@link ThreadInfo} corresponding 323 * to the thread details specified. 324 * 325 * @param threadId the id of the thread on which this 326 * new instance will be based. 327 * @param threadName the name of the thread on which 328 * this new instance will be based. 329 * @param threadState the state of the thread on which 330 * this new instance will be based. 331 * @param blockedCount the number of times the thread 332 * has been blocked. 333 * @param blockedTime the accumulated number of milliseconds 334 * the specified thread has been blocked 335 * (only used with contention monitoring enabled) 336 * @param lockName the name of the monitor lock the thread is waiting for 337 * (only used if blocked) 338 * @param lockOwnerId the id of the thread which owns the monitor 339 * lock, or <code>-1</code> if it doesn't have an owner 340 * (only used if blocked) 341 * @param lockOwnerName the name of the thread which owns the monitor 342 * lock, or <code>null</code> if it doesn't have an 343 * owner (only used if blocked) 344 * @param waitedCount the number of times the thread has been in a 345 * waiting state. 346 * @param waitedTime the accumulated number of milliseconds the 347 * specified thread has been waiting 348 * (only used with contention monitoring enabled) 349 * @param isInNative true if the thread is in a native method. 350 * @param isSuspended true if the thread is suspended. 351 * @param trace the stack trace of the thread to a pre-determined 352 * depth (see VMThreadMXBeanImpl) 353 * @param lockedMonitors an array of {@link MonitorInfo} objects 354 * representing locks held on object monitors 355 * by the thread. 356 * @param lockedSynchronizers an array of {@link LockInfo} objects 357 * representing locks held on ownable 358 * synchronizers by the thread. 359 * 360 * @since 1.6 361 */ 362 private ThreadInfo(long threadId, String threadName, Thread.State threadState, 363 long blockedCount, long blockedTime, String lockName, 364 long lockOwnerId, String lockOwnerName, long waitedCount, 365 long waitedTime, boolean isInNative, boolean isSuspended, 366 StackTraceElement[] trace, MonitorInfo[] lockedMonitors, 367 LockInfo[] lockedSynchronizers) 368 { 369 this.threadId = threadId; 370 this.threadName = threadName; 371 this.threadState = threadState; 372 this.blockedCount = blockedCount; 373 this.blockedTime = blockedTime; 374 this.lockName = lockName; 375 this.lockOwnerId = lockOwnerId; 376 this.lockOwnerName = lockOwnerName; 377 this.waitedCount = waitedCount; 378 this.waitedTime = waitedTime; 379 this.isInNative = isInNative; 380 this.isSuspended = isSuspended; 381 this.trace = trace; 382 this.lockedMonitors = lockedMonitors; 383 this.lockedSynchronizers = lockedSynchronizers; 384 } 385 386 /** 387 * Checks for an attribute in a {@link CompositeData} structure 388 * with the correct type. 389 * 390 * @param ctype the composite data type to check. 391 * @param name the name of the attribute. 392 * @param type the type to check for. 393 * @throws IllegalArgumentException if the attribute is absent 394 * or of the wrong type. 395 */ 396 static void checkAttribute(CompositeType ctype, String name, 397 OpenType type) 398 throws IllegalArgumentException 399 { 400 OpenType foundType = ctype.getType(name); 401 if (foundType == null) 402 throw new IllegalArgumentException("Could not find a field named " + 403 name); 404 if (!(foundType.equals(type))) 405 throw new IllegalArgumentException("Field " + name + " is not of " + 406 "type " + type.getClassName()); 407 } 408 409 /** 410 * Returns the {@link javax.management.openmbean.CompositeType} for 411 * a {@link StackTraceElement}. 412 * 413 * @return the type for the stack trace element. 414 */ 415 static CompositeType getStackTraceType() 416 { 417 if (seType == null) 418 try 419 { 420 seType = new CompositeType(StackTraceElement.class.getName(), 421 "An element of a stack trace", 422 new String[] { "className", "methodName", 423 "fileName", "lineNumber", 424 "nativeMethod" 425 }, 426 new String[] { "Name of the class", 427 "Name of the method", 428 "Name of the source code file", 429 "Line number", 430 "True if this is a native method" 431 }, 432 new OpenType[] { 433 SimpleType.STRING, SimpleType.STRING, 434 SimpleType.STRING, SimpleType.INTEGER, 435 SimpleType.BOOLEAN 436 }); 437 } 438 catch (OpenDataException e) 439 { 440 throw new IllegalStateException("Something went wrong in creating " + 441 "the composite data type for the " + 442 "stack trace element.", e); 443 } 444 return seType; 445 } 446 447 /** 448 * <p> 449 * Returns a {@link ThreadInfo} instance using the values 450 * given in the supplied 451 * {@link javax.management.openmbean.CompositeData} object. 452 * The composite data instance should contain the following 453 * attributes with the specified types: 454 * </p> 455 * <table> 456 * <th><td>Name</td><td>Type</td></th> 457 * <tr><td>threadId</td><td>java.lang.Long</td></tr> 458 * <tr><td>threadName</td><td>java.lang.String</td></tr> 459 * <tr><td>threadState</td><td>java.lang.String</td></tr> 460 * <tr><td>suspended</td><td>java.lang.Boolean</td></tr> 461 * <tr><td>inNative</td><td>java.lang.Boolean</td></tr> 462 * <tr><td>blockedCount</td><td>java.lang.Long</td></tr> 463 * <tr><td>blockedTime</td><td>java.lang.Long</td></tr> 464 * <tr><td>waitedCount</td><td>java.lang.Long</td></tr> 465 * <tr><td>waitedTime</td><td>java.lang.Long</td></tr> 466 * <tr><td>lockName</td><td>java.lang.String</td></tr> 467 * <tr><td>lockOwnerId</td><td>java.lang.Long</td></tr> 468 * <tr><td>lockOwnerName</td><td>java.lang.String</td></tr> 469 * <tr><td>stackTrace</td><td>javax.management.openmbean.CompositeData[] 470 * </td></tr> 471 * </table> 472 * <p> 473 * The stack trace is further described as: 474 * </p> 475 * <table> 476 * <th><td>Name</td><td>Type</td></th> 477 * <tr><td>className</td><td>java.lang.String</td></tr> 478 * <tr><td>methodName</td><td>java.lang.String</td></tr> 479 * <tr><td>fileName</td><td>java.lang.String</td></tr> 480 * <tr><td>lineNumber</td><td>java.lang.Integer</td></tr> 481 * <tr><td>nativeMethod</td><td>java.lang.Boolean</td></tr> 482 * </table> 483 * 484 * @param data the composite data structure to take values from. 485 * @return a new instance containing the values from the 486 * composite data structure, or <code>null</code> 487 * if the data structure was also <code>null</code>. 488 * @throws IllegalArgumentException if the composite data structure 489 * does not match the structure 490 * outlined above. 491 */ 492 public static ThreadInfo from(CompositeData data) 493 { 494 if (data == null) 495 return null; 496 CompositeType type = data.getCompositeType(); 497 checkAttribute(type, "ThreadId", SimpleType.LONG); 498 checkAttribute(type, "ThreadName", SimpleType.STRING); 499 checkAttribute(type, "ThreadState", SimpleType.STRING); 500 checkAttribute(type, "Suspended", SimpleType.BOOLEAN); 501 checkAttribute(type, "InNative", SimpleType.BOOLEAN); 502 checkAttribute(type, "BlockedCount", SimpleType.LONG); 503 checkAttribute(type, "BlockedTime", SimpleType.LONG); 504 checkAttribute(type, "WaitedCount", SimpleType.LONG); 505 checkAttribute(type, "WaitedTime", SimpleType.LONG); 506 checkAttribute(type, "LockName", SimpleType.STRING); 507 checkAttribute(type, "LockOwnerId", SimpleType.LONG); 508 checkAttribute(type, "LockOwnerName", SimpleType.STRING); 509 try 510 { 511 checkAttribute(type, "StackTrace", 512 new ArrayType(1, getStackTraceType())); 513 } 514 catch (OpenDataException e) 515 { 516 throw new IllegalStateException("Something went wrong in creating " + 517 "the array for the stack trace element.", 518 e); 519 } 520 OpenType foundType = type.getType("LockedMonitors"); 521 if (foundType != null) 522 try 523 { 524 CompositeType mType = new CompositeType(MonitorInfo.class.getName(), 525 "Information on a object monitor lock", 526 new String[] { "ClassName", 527 "IdentityHashCode", 528 "LockedStackDepth", 529 "LockedStackFrame" 530 }, 531 new String[] { "Name of the class", 532 "Identity hash code " + 533 "of the class", 534 "Stack depth at time " + 535 "of lock", 536 "Stack frame at time " + 537 "of lock", 538 }, 539 new OpenType[] { 540 SimpleType.STRING, SimpleType.INTEGER, 541 SimpleType.INTEGER, getStackTraceType() 542 }); 543 if (!(foundType.equals(new ArrayType(1, mType)))) 544 throw new IllegalArgumentException("Field LockedMonitors is not of " + 545 "type " + mType.getClassName()); 546 } 547 catch (OpenDataException e) 548 { 549 throw new IllegalStateException("Something went wrong in creating " + 550 "the composite data type for the " + 551 "object monitor information array.", e); 552 } 553 foundType = type.getType("LockedSynchronizers"); 554 if (foundType != null) 555 try 556 { 557 CompositeType lType = new CompositeType(LockInfo.class.getName(), 558 "Information on a lock", 559 new String[] { "ClassName", 560 "IdentityHashCode" 561 }, 562 new String[] { "Name of the class", 563 "Identity hash code " + 564 "of the class" 565 }, 566 new OpenType[] { 567 SimpleType.STRING, SimpleType.INTEGER 568 }); 569 if (!(foundType.equals(new ArrayType(1, lType)))) 570 throw new IllegalArgumentException("Field LockedSynchronizers is not of " + 571 "type " + lType.getClassName()); 572 } 573 catch (OpenDataException e) 574 { 575 throw new IllegalStateException("Something went wrong in creating " + 576 "the composite data type for the " + 577 "ownable synchronizerinformation array.", e); 578 } 579 CompositeData[] dTraces = (CompositeData[]) data.get("StackTrace"); 580 StackTraceElement[] traces = new StackTraceElement[dTraces.length]; 581 for (int a = 0; a < dTraces.length; ++a) 582 /* FIXME: We can't use the boolean as there is no available 583 constructor. */ 584 traces[a] = 585 new StackTraceElement((String) dTraces[a].get("ClassName"), 586 (String) dTraces[a].get("MethodName"), 587 (String) dTraces[a].get("FileName"), 588 ((Integer) 589 dTraces[a].get("LineNumber")).intValue()); 590 MonitorInfo[] mInfo; 591 if (data.containsKey("LockedMonitors")) 592 { 593 CompositeData[] dmInfos = (CompositeData[]) data.get("LockedMonitors"); 594 mInfo = new MonitorInfo[dmInfos.length]; 595 for (int a = 0; a < dmInfos.length; ++a) 596 mInfo[a] = MonitorInfo.from(dmInfos[a]); 597 } 598 else 599 mInfo = new MonitorInfo[]{}; 600 LockInfo[] lInfo; 601 if (data.containsKey("LockedSynchronizers")) 602 { 603 CompositeData[] dlInfos = (CompositeData[]) data.get("LockedSynchronizers"); 604 lInfo = new LockInfo[dlInfos.length]; 605 for (int a = 0; a < dlInfos.length; ++a) 606 lInfo[a] = new LockInfo((String) dlInfos[a].get("ClassName"), 607 (Integer) dlInfos[a].get("IdentityHashCode")); 608 } 609 else 610 lInfo = new LockInfo[]{}; 611 return new ThreadInfo(((Long) data.get("ThreadId")).longValue(), 612 (String) data.get("ThreadName"), 613 Thread.State.valueOf((String) data.get("ThreadState")), 614 ((Long) data.get("BlockedCount")).longValue(), 615 ((Long) data.get("BlockedTime")).longValue(), 616 (String) data.get("LockName"), 617 ((Long) data.get("LockOwnerId")).longValue(), 618 (String) data.get("LockOwnerName"), 619 ((Long) data.get("WaitedCount")).longValue(), 620 ((Long) data.get("WaitedTime")).longValue(), 621 ((Boolean) data.get("InNative")).booleanValue(), 622 ((Boolean) data.get("Suspended")).booleanValue(), 623 traces, mInfo, lInfo); 624 } 625 626 /** 627 * Returns the number of times this thread has been 628 * in the {@link java.lang.Thread.State#BLOCKED} state. 629 * A thread enters this state when it is waiting to 630 * obtain an object's monitor. This may occur either 631 * on entering a synchronized method for the first time, 632 * or on re-entering it following a call to 633 * {@link java.lang.Object#wait()}. 634 * 635 * @return the number of times this thread has been blocked. 636 */ 637 public long getBlockedCount() 638 { 639 return blockedCount; 640 } 641 642 /** 643 * <p> 644 * Returns the accumulated number of milliseconds this 645 * thread has been in the 646 * {@link java.lang.Thread.State#BLOCKED} state 647 * since thread contention monitoring was last enabled. 648 * A thread enters this state when it is waiting to 649 * obtain an object's monitor. This may occur either 650 * on entering a synchronized method for the first time, 651 * or on re-entering it following a call to 652 * {@link java.lang.Object#wait()}. 653 * </p> 654 * <p> 655 * Use of this method requires virtual machine support 656 * for thread contention monitoring and for this support 657 * to be enabled. 658 * </p> 659 * 660 * @return the accumulated time (in milliseconds) that this 661 * thread has spent in the blocked state, since 662 * thread contention monitoring was enabled, or -1 663 * if thread contention monitoring is disabled. 664 * @throws UnsupportedOperationException if the virtual 665 * machine does not 666 * support contention 667 * monitoring. 668 * @see ThreadMXBean#isThreadContentionMonitoringEnabled() 669 * @see ThreadMXBean#isThreadContentionMonitoringSupported() 670 */ 671 public long getBlockedTime() 672 { 673 if (bean == null) 674 bean = ManagementFactory.getThreadMXBean(); 675 // Will throw UnsupportedOperationException for us 676 if (bean.isThreadContentionMonitoringEnabled()) 677 return blockedTime; 678 else 679 return -1; 680 } 681 682 /** 683 * Returns an array of {@link MonitorInfo} objects representing 684 * information on the locks on object monitors held by the thread. 685 * If no locks are held, or such information was not requested 686 * on creating this {@link ThreadInfo} object, a zero-length 687 * array will be returned. 688 * 689 * @return information on object monitors locked by this thread. 690 */ 691 public MonitorInfo[] getLockedMonitors() 692 { 693 return lockedMonitors; 694 } 695 696 /** 697 * Returns an array of {@link LockInfo} objects representing 698 * information on the locks on ownable synchronizers held by the thread. 699 * If no locks are held, or such information was not requested 700 * on creating this {@link ThreadInfo} object, a zero-length 701 * array will be returned. 702 * 703 * @return information on ownable synchronizers locked by this thread. 704 */ 705 public LockInfo[] getLockedSynchronizers() 706 { 707 return lockedSynchronizers; 708 } 709 710 /** 711 * <p> 712 * Returns a {@link LockInfo} object representing the 713 * lock on which this thread is blocked. If the thread 714 * is not blocked, this method returns <code>null</code>. 715 * </p> 716 * <p> 717 * The thread may be blocked due to one of three reasons: 718 * </p> 719 * <ol> 720 * <li>The thread is in the <code>BLOCKED</code> state 721 * waiting to acquire an object monitor in order to enter 722 * a synchronized method or block.</li> 723 * <li>The thread is in the <code>WAITING</code> or 724 * <code>TIMED_WAITING</code> state due to a call to 725 * {@link java.lang.Object#wait()}.</li> 726 * <li>The thread is in the <code>WAITING</code> or 727 * <code>TIMED_WAITING</code> state due to a call 728 * to {@link java.util.concurrent.locks.LockSupport#park()}. 729 * The lock is the return value of 730 * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> 731 * </ol> 732 * 733 * @return a {@link LockInfo} object representing the lock on 734 * which the thread is blocked, or <code>null</code> if 735 * the thread isn't blocked. 736 * @since 1.6 737 * @see #getLockName() 738 */ 739 public LockInfo getLockInfo() 740 { 741 String lockName = getLockName(); 742 int at = lockName.indexOf('@'); 743 return new LockInfo(lockName.substring(0, at), 744 Integer.decode(lockName.substring(at + 1))); 745 } 746 747 /** 748 * <p> 749 * Returns a {@link java.lang.String} representation of 750 * the lock on which this thread is blocked. If 751 * the thread is not blocked, this method returns 752 * <code>null</code>. 753 * </p> 754 * <p> 755 * The returned {@link java.lang.String} is constructed 756 * using the class name and identity hashcode (usually 757 * the memory address of the object) of the lock. The 758 * two are separated by the '@' character, and the identity 759 * hashcode is represented in hexadecimal. Thus, for a 760 * lock, <code>l</code>, the returned value is 761 * the result of concatenating 762 * <code>l.getClass().getName()</code>, <code>"@"</code> 763 * and 764 * <code>Integer.toHexString(System.identityHashCode(l))</code>. 765 * The value is only unique to the extent that the identity 766 * hash code is also unique. The value is the same as would 767 * be returned by <code>getLockInfo().toString()</code> 768 * </p> 769 * 770 * @return a string representing the lock on which this 771 * thread is blocked, or <code>null</code> if 772 * the thread is not blocked. 773 */ 774 public String getLockName() 775 { 776 if (!isThreadBlocked()) 777 return null; 778 return lockName; 779 } 780 781 /** 782 * Returns the identifier of the thread which owns the 783 * monitor lock this thread is waiting for. -1 is returned 784 * if either this thread is not blocked, or the lock is 785 * not held by any other thread. 786 * 787 * @return the thread identifier of thread holding the lock 788 * this thread is waiting for, or -1 if the thread 789 * is not blocked or the lock is not held by another 790 * thread. 791 */ 792 public long getLockOwnerId() 793 { 794 if (!isThreadBlocked()) 795 return -1; 796 return lockOwnerId; 797 } 798 799 /** 800 * Returns the name of the thread which owns the 801 * monitor lock this thread is waiting for. <code>null</code> 802 * is returned if either this thread is not blocked, 803 * or the lock is not held by any other thread. 804 * 805 * @return the thread identifier of thread holding the lock 806 * this thread is waiting for, or <code>null</code> 807 * if the thread is not blocked or the lock is not 808 * held by another thread. 809 */ 810 public String getLockOwnerName() 811 { 812 if (!isThreadBlocked()) 813 return null; 814 return lockOwnerName; 815 } 816 817 /** 818 * <p> 819 * Returns the stack trace of this thread to the depth 820 * specified on creation of this {@link ThreadInfo} 821 * object. If the depth is zero, an empty array will 822 * be returned. For non-zero arrays, the elements 823 * start with the most recent trace at position zero. 824 * The bottom of the stack represents the oldest method 825 * invocation which meets the depth requirements. 826 * </p> 827 * <p> 828 * Some virtual machines may not be able to return 829 * stack trace information for a thread. In these 830 * cases, an empty array will also be returned. 831 * </p> 832 * 833 * @return an array of {@link java.lang.StackTraceElement}s 834 * representing the trace of this thread. 835 */ 836 public StackTraceElement[] getStackTrace() 837 { 838 return trace; 839 } 840 841 /** 842 * Returns the identifier of the thread associated with 843 * this instance of {@link ThreadInfo}. 844 * 845 * @return the thread's identifier. 846 */ 847 public long getThreadId() 848 { 849 return threadId; 850 } 851 852 /** 853 * Returns the name of the thread associated with 854 * this instance of {@link ThreadInfo}. 855 * 856 * @return the thread's name. 857 */ 858 public String getThreadName() 859 { 860 return threadName; 861 } 862 863 /** 864 * Returns the state of the thread associated with 865 * this instance of {@link ThreadInfo}. 866 * 867 * @return the thread's state. 868 */ 869 public Thread.State getThreadState() 870 { 871 return threadState; 872 } 873 874 /** 875 * Returns the number of times this thread has been 876 * in the {@link java.lang.Thread.State#WAITING} 877 * or {@link java.lang.Thread.State#TIMED_WAITING} state. 878 * A thread enters one of these states when it is waiting 879 * due to a call to {@link java.lang.Object.wait()}, 880 * {@link java.lang.Object.join()} or 881 * {@link java.lang.concurrent.locks.LockSupport.park()}, 882 * either with an infinite or timed delay, respectively. 883 * 884 * @return the number of times this thread has been waiting. 885 */ 886 public long getWaitedCount() 887 { 888 return waitedCount; 889 } 890 891 /** 892 * <p> 893 * Returns the accumulated number of milliseconds this 894 * thread has been in the 895 * {@link java.lang.Thread.State#WAITING} or 896 * {@link java.lang.Thread.State#TIMED_WAITING} state, 897 * since thread contention monitoring was last enabled. 898 * A thread enters one of these states when it is waiting 899 * due to a call to {@link java.lang.Object.wait()}, 900 * {@link java.lang.Object.join()} or 901 * {@link java.lang.concurrent.locks.LockSupport.park()}, 902 * either with an infinite or timed delay, respectively. 903 * </p> 904 * <p> 905 * Use of this method requires virtual machine support 906 * for thread contention monitoring and for this support 907 * to be enabled. 908 * </p> 909 * 910 * @return the accumulated time (in milliseconds) that this 911 * thread has spent in one of the waiting states, since 912 * thread contention monitoring was enabled, or -1 913 * if thread contention monitoring is disabled. 914 * @throws UnsupportedOperationException if the virtual 915 * machine does not 916 * support contention 917 * monitoring. 918 * @see ThreadMXBean#isThreadContentionMonitoringEnabled() 919 * @see ThreadMXBean#isThreadContentionMonitoringSupported() 920 */ 921 public long getWaitedTime() 922 { 923 if (bean == null) 924 bean = ManagementFactory.getThreadMXBean(); 925 // Will throw UnsupportedOperationException for us 926 if (bean.isThreadContentionMonitoringEnabled()) 927 return waitedTime; 928 else 929 return -1; 930 } 931 932 /** 933 * Returns true if the thread is in a native method. This 934 * excludes native code which forms part of the virtual 935 * machine itself, or which results from Just-In-Time 936 * compilation. 937 * 938 * @return true if the thread is in a native method, false 939 * otherwise. 940 */ 941 public boolean isInNative() 942 { 943 return isInNative; 944 } 945 946 /** 947 * Returns true if the thread has been suspended using 948 * {@link java.lang.Thread#suspend()}. 949 * 950 * @return true if the thread is suspended, false otherwise. 951 */ 952 public boolean isSuspended() 953 { 954 return isSuspended; 955 } 956 957 /** 958 * Returns a {@link java.lang.String} representation of 959 * this {@link ThreadInfo} object. This takes the form 960 * <code>java.lang.management.ThreadInfo[id=tid, name=n, 961 * state=s, blockedCount=bc, waitedCount=wc, isInNative=iin, 962 * isSuspended=is]</code>, where <code>tid</code> is 963 * the thread identifier, <code>n</code> is the 964 * thread name, <code>s</code> is the thread state, 965 * <code>bc</code> is the blocked state count, 966 * <code>wc</code> is the waiting state count and 967 * <code>iin</code> and <code>is</code> are boolean 968 * flags to indicate the thread is in native code or 969 * suspended respectively. If the thread is blocked, 970 * <code>lock=l, lockOwner=lo</code> is also included, 971 * where <code>l</code> is the lock waited for, and 972 * <code>lo</code> is the thread which owns the lock 973 * (or null if there is no owner). 974 * 975 * @return the string specified above. 976 */ 977 public String toString() 978 { 979 return getClass().getName() + 980 "[id=" + threadId + 981 ", name=" + threadName + 982 ", state=" + threadState + 983 ", blockedCount=" + blockedCount + 984 ", waitedCount=" + waitedCount + 985 ", isInNative=" + isInNative + 986 ", isSuspended=" + isSuspended + 987 (isThreadBlocked() ? 988 ", lockOwnerId=" + lockOwnerId + 989 ", lockOwnerName=" + lockOwnerName : "") + 990 ", lockedMonitors=" + Arrays.toString(lockedMonitors) + 991 ", lockedSynchronizers=" + Arrays.toString(lockedSynchronizers) + 992 "]"; 993 } 994 995 /** 996 * <p> 997 * Returns true if the thread is in a blocked state. 998 * The thread is regarded as blocked if: 999 * </p> 1000 * <ol> 1001 * <li>The thread is in the <code>BLOCKED</code> state 1002 * waiting to acquire an object monitor in order to enter 1003 * a synchronized method or block.</li> 1004 * <li>The thread is in the <code>WAITING</code> or 1005 * <code>TIMED_WAITING</code> state due to a call to 1006 * {@link java.lang.Object#wait()}.</li> 1007 * <li>The thread is in the <code>WAITING</code> or 1008 * <code>TIMED_WAITING</code> state due to a call 1009 * to {@link java.util.concurrent.locks.LockSupport#park()}. 1010 * The lock is the return value of 1011 * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> 1012 * </ol> 1013 * 1014 * @return true if the thread is blocked. 1015 */ 1016 private boolean isThreadBlocked() 1017 { 1018 return (threadState == Thread.State.BLOCKED || 1019 threadState == Thread.State.WAITING || 1020 threadState == Thread.State.TIMED_WAITING); 1021 } 1022 1023 }