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 }