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