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