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