Source for java.lang.management.ThreadInfo

   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: }