0N/A/*
2362N/A * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
0N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
4378N/A/*
0N/A */
0N/A
0N/Aimport static java.lang.management.ManagementFactory.*;
0N/Aimport java.lang.management.ThreadMXBean;
0N/Aimport java.lang.management.ThreadInfo;
0N/Aimport java.lang.management.LockInfo;
0N/Aimport java.lang.management.MonitorInfo;
0N/Aimport javax.management.*;
0N/Aimport java.io.*;
0N/A
0N/A/**
0N/A * Example of using the java.lang.management API to dump stack trace
0N/A * and to perform deadlock detection.
0N/A *
0N/A * @author Mandy Chung
0N/A */
0N/Apublic class ThreadMonitor {
0N/A private MBeanServerConnection server;
0N/A private ThreadMXBean tmbean;
0N/A private ObjectName objname;
0N/A
0N/A // default - JDK 6+ VM
0N/A private String findDeadlocksMethodName = "findDeadlockedThreads";
0N/A private boolean canDumpLocks = true;
0N/A
0N/A /**
0N/A * Constructs a ThreadMonitor object to get thread information
0N/A * in a remote JVM.
0N/A */
0N/A public ThreadMonitor(MBeanServerConnection server) throws IOException {
0N/A this.server = server;
0N/A this.tmbean = newPlatformMXBeanProxy(server,
0N/A THREAD_MXBEAN_NAME,
0N/A ThreadMXBean.class);
0N/A try {
0N/A objname = new ObjectName(THREAD_MXBEAN_NAME);
0N/A } catch (MalformedObjectNameException e) {
0N/A // should not reach here
0N/A InternalError ie = new InternalError(e.getMessage());
0N/A ie.initCause(e);
0N/A throw ie;
0N/A }
0N/A parseMBeanInfo();
0N/A }
0N/A
0N/A /**
0N/A * Constructs a ThreadMonitor object to get thread information
0N/A * in the local JVM.
0N/A */
0N/A public ThreadMonitor() {
0N/A this.tmbean = getThreadMXBean();
0N/A }
0N/A
0N/A /**
0N/A * Prints the thread dump information to System.out.
0N/A */
0N/A public void threadDump() {
0N/A if (canDumpLocks) {
0N/A if (tmbean.isObjectMonitorUsageSupported() &&
0N/A tmbean.isSynchronizerUsageSupported()) {
0N/A // Print lock info if both object monitor usage
0N/A // and synchronizer usage are supported.
0N/A // This sample code can be modified to handle if
0N/A // either monitor usage or synchronizer usage is supported.
0N/A dumpThreadInfoWithLocks();
0N/A }
0N/A } else {
0N/A dumpThreadInfo();
0N/A }
0N/A }
0N/A
0N/A private void dumpThreadInfo() {
0N/A System.out.println("Full Java thread dump");
0N/A long[] tids = tmbean.getAllThreadIds();
0N/A ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
0N/A for (ThreadInfo ti : tinfos) {
0N/A printThreadInfo(ti);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Prints the thread dump information with locks info to System.out.
0N/A */
0N/A private void dumpThreadInfoWithLocks() {
0N/A System.out.println("Full Java thread dump with locks info");
0N/A
0N/A ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true);
0N/A for (ThreadInfo ti : tinfos) {
0N/A printThreadInfo(ti);
0N/A LockInfo[] syncs = ti.getLockedSynchronizers();
0N/A printLockInfo(syncs);
0N/A }
0N/A System.out.println();
0N/A }
0N/A
0N/A private static String INDENT = " ";
0N/A
0N/A private void printThreadInfo(ThreadInfo ti) {
0N/A // print thread information
0N/A printThread(ti);
0N/A
0N/A // print stack trace with locks
0N/A StackTraceElement[] stacktrace = ti.getStackTrace();
0N/A MonitorInfo[] monitors = ti.getLockedMonitors();
0N/A for (int i = 0; i < stacktrace.length; i++) {
0N/A StackTraceElement ste = stacktrace[i];
0N/A System.out.println(INDENT + "at " + ste.toString());
0N/A for (MonitorInfo mi : monitors) {
0N/A if (mi.getLockedStackDepth() == i) {
0N/A System.out.println(INDENT + " - locked " + mi);
0N/A }
0N/A }
0N/A }
0N/A System.out.println();
0N/A }
0N/A
0N/A private void printThread(ThreadInfo ti) {
0N/A StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" +
0N/A " Id=" + ti.getThreadId() +
0N/A " in " + ti.getThreadState());
0N/A if (ti.getLockName() != null) {
0N/A sb.append(" on lock=" + ti.getLockName());
0N/A }
0N/A if (ti.isSuspended()) {
0N/A sb.append(" (suspended)");
0N/A }
0N/A if (ti.isInNative()) {
0N/A sb.append(" (running in native)");
0N/A }
0N/A System.out.println(sb.toString());
0N/A if (ti.getLockOwnerName() != null) {
0N/A System.out.println(INDENT + " owned by " + ti.getLockOwnerName() +
0N/A " Id=" + ti.getLockOwnerId());
0N/A }
0N/A }
0N/A
4123N/A private void printMonitorInfo(ThreadInfo ti) {
4123N/A MonitorInfo[] monitors = ti.getLockedMonitors();
0N/A System.out.println(INDENT + "Locked monitors: count = " + monitors.length);
0N/A for (MonitorInfo mi : monitors) {
0N/A System.out.println(INDENT + " - " + mi + " locked at ");
0N/A System.out.println(INDENT + " " + mi.getLockedStackDepth() +
0N/A " " + mi.getLockedStackFrame());
0N/A }
0N/A }
0N/A
0N/A private void printLockInfo(LockInfo[] locks) {
0N/A System.out.println(INDENT + "Locked synchronizers: count = " + locks.length);
0N/A for (LockInfo li : locks) {
0N/A System.out.println(INDENT + " - " + li);
0N/A }
0N/A System.out.println();
0N/A }
0N/A
0N/A /**
0N/A * Checks if any threads are deadlocked. If any, print
0N/A * the thread dump information.
0N/A */
0N/A public boolean findDeadlock() {
0N/A long[] tids;
0N/A if (findDeadlocksMethodName.equals("findDeadlockedThreads") &&
0N/A tmbean.isSynchronizerUsageSupported()) {
0N/A tids = tmbean.findDeadlockedThreads();
0N/A if (tids == null) {
0N/A return false;
0N/A }
0N/A
0N/A System.out.println("Deadlock found :-");
0N/A ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
0N/A for (ThreadInfo ti : infos) {
0N/A printThreadInfo(ti);
4123N/A printMonitorInfo(ti);
0N/A printLockInfo(ti.getLockedSynchronizers());
0N/A System.out.println();
0N/A }
0N/A } else {
0N/A tids = tmbean.findMonitorDeadlockedThreads();
0N/A if (tids == null) {
0N/A return false;
0N/A }
0N/A ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
0N/A for (ThreadInfo ti : infos) {
0N/A // print thread information
0N/A printThreadInfo(ti);
0N/A }
0N/A }
0N/A
0N/A return true;
0N/A }
0N/A
0N/A
0N/A private void parseMBeanInfo() throws IOException {
0N/A try {
0N/A MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations();
0N/A
0N/A // look for findDeadlockedThreads operations;
0N/A boolean found = false;
0N/A for (MBeanOperationInfo op : mopis) {
0N/A if (op.getName().equals(findDeadlocksMethodName)) {
0N/A found = true;
0N/A break;
0N/A }
0N/A }
0N/A if (!found) {
0N/A // if findDeadlockedThreads operation doesn't exist,
0N/A // the target VM is running on JDK 5 and details about
0N/A // synchronizers and locks cannot be dumped.
0N/A findDeadlocksMethodName = "findMonitorDeadlockedThreads";
0N/A canDumpLocks = false;
0N/A }
0N/A } catch (IntrospectionException e) {
0N/A InternalError ie = new InternalError(e.getMessage());
0N/A ie.initCause(e);
0N/A throw ie;
0N/A } catch (InstanceNotFoundException e) {
0N/A InternalError ie = new InternalError(e.getMessage());
0N/A ie.initCause(e);
0N/A throw ie;
0N/A } catch (ReflectionException e) {
0N/A InternalError ie = new InternalError(e.getMessage());
0N/A ie.initCause(e);
0N/A throw ie;
0N/A }
0N/A }
0N/A}