Java/Development Class/Java Management API

Материал из Java эксперт
Перейти к: навигация, поиск

Demo code which plots the memory usage by all memory pools

   
/*
 * @(#)MemoryMonitor.java 1.3 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * @(#)MemoryMonitor.java 1.3 05/11/17
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.util.Date;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
/**
 * Demo code which plots the memory usage by all memory pools. The memory usage
 * is sampled at some time interval using java.lang.management API. This demo
 * code is modified based java2d MemoryMonitor demo.
 */
public class MemoryMonitor extends JPanel {
  static JCheckBox dateStampCB = new JCheckBox("Output Date Stamp");
  public Surface surf;
  JPanel controls;
  boolean doControls;
  JTextField tf;
  // Get memory pools.
  static java.util.List<MemoryPoolMXBean> mpools = ManagementFactory.getMemoryPoolMXBeans();
  // Total number of memory pools.
  static int numPools = mpools.size();
  public MemoryMonitor() {
    setLayout(new BorderLayout());
    setBorder(new TitledBorder(new EtchedBorder(), "Memory Monitor"));
    add(surf = new Surface());
    controls = new JPanel();
    controls.setPreferredSize(new Dimension(135, 80));
    Font font = new Font("serif", Font.PLAIN, 10);
    JLabel label = new JLabel("Sample Rate");
    label.setFont(font);
    label.setForeground(Color.red);
    controls.add(label);
    tf = new JTextField("1000");
    tf.setPreferredSize(new Dimension(45, 20));
    controls.add(tf);
    controls.add(label = new JLabel("ms"));
    label.setFont(font);
    label.setForeground(Color.red);
    controls.add(dateStampCB);
    dateStampCB.setFont(font);
    addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        removeAll();
        if ((doControls = !doControls)) {
          surf.stop();
          add(controls);
        } else {
          try {
            surf.sleepAmount = Long.parseLong(tf.getText().trim());
          } catch (Exception ex) {
          }
          surf.start();
          add(surf);
        }
        validate();
        repaint();
      }
    });
  }
  public class Surface extends JPanel implements Runnable {
    public Thread thread;
    public long sleepAmount = 1000;
    public int usageHistCount = 20000;
    private int w, h;
    private BufferedImage bimg;
    private Graphics2D big;
    private Font font = new Font("Times New Roman", Font.PLAIN, 11);
    private int columnInc;
    private float usedMem[][];
    private int ptNum[];
    private int ascent, descent;
    private Rectangle graphOutlineRect = new Rectangle();
    private Rectangle2D mfRect = new Rectangle2D.Float();
    private Rectangle2D muRect = new Rectangle2D.Float();
    private Line2D graphLine = new Line2D.Float();
    private Color graphColor = new Color(46, 139, 87);
    private Color mfColor = new Color(0, 100, 0);
    private String usedStr;
    public Surface() {
      setBackground(Color.black);
      addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
          if (thread == null)
            start();
          else
            stop();
        }
      });
      int i = 0;
      usedMem = new float[numPools][];
      ptNum = new int[numPools];
    }
    public Dimension getMinimumSize() {
      return getPreferredSize();
    }
    public Dimension getMaximumSize() {
      return getPreferredSize();
    }
    public Dimension getPreferredSize() {
      return new Dimension(135, 80);
    }
    public void paint(Graphics g) {
      if (big == null) {
        return;
      }
      big.setBackground(getBackground());
      big.clearRect(0, 0, w, h);
      h = h / ((numPools + numPools % 2) / 2);
      w = w / 2;
      int k = 0; // index of memory pool.
      for (int i = 0; i < 2; i++) {
        for (int j = 0; j < (numPools + numPools % 2) / 2; j++) {
          plotMemoryUsage(w * i, h * j, w, h, k);
          if (++k >= numPools) {
            i = 3;
            j = (numPools + numPools % 2) / 2;
            break;
          }
        }
      }
      g.drawImage(bimg, 0, 0, this);
    }
    public void plotMemoryUsage(int x1, int y1, int x2, int y2, int npool) {
      MemoryPoolMXBean mp = mpools.get(npool);
      float usedMemory = mp.getUsage().getUsed();
      float totalMemory = mp.getUsage().getMax();
      // .. Draw allocated and used strings ..
      big.setColor(Color.green);
      // Print Max memory allocated for this memory pool.
      big.drawString(String.valueOf((int) totalMemory / 1024) + "K Max ", x1 + 4.0f, (float) y1
          + ascent + 0.5f);
      big.setColor(Color.yellow);
      // Print the memory pool name.
      big.drawString(mp.getName(), x1 + x2 / 2, (float) y1 + ascent + 0.5f);
      // Print the memory used by this memory pool.
      usedStr = String.valueOf((int) usedMemory / 1024) + "K used";
      big.setColor(Color.green);
      big.drawString(usedStr, x1 + 4, y1 + y2 - descent);
      // Calculate remaining size
      float ssH = ascent + descent;
      float remainingHeight = (float) (y2 - (ssH * 2) - 0.5f);
      float blockHeight = remainingHeight / 10;
      float blockWidth = 20.0f;
      float remainingWidth = (float) (x2 - blockWidth - 10);
      // .. Memory Free ..
      big.setColor(mfColor);
      int MemUsage = (int) (((totalMemory - usedMemory) / totalMemory) * 10);
      int i = 0;
      for (; i < MemUsage; i++) {
        mfRect.setRect(x1 + 5, (float) y1 + ssH + i * blockHeight, blockWidth,
            (float) blockHeight - 1);
        big.fill(mfRect);
      }
      // .. Memory Used ..
      big.setColor(Color.green);
      for (; i < 10; i++) {
        muRect.setRect(x1 + 5, (float) y1 + ssH + i * blockHeight, blockWidth,
            (float) blockHeight - 1);
        big.fill(muRect);
      }
      // .. Draw History Graph ..
      if (remainingWidth <= 30)
        remainingWidth = (float) 30;
      if (remainingHeight <= ssH)
        remainingHeight = (float) ssH;
      big.setColor(graphColor);
      int graphX = x1 + 30;
      int graphY = y1 + (int) ssH;
      int graphW = (int) remainingWidth;
      int graphH = (int) remainingHeight;
      graphOutlineRect.setRect(graphX, graphY, graphW, graphH);
      big.draw(graphOutlineRect);
      int graphRow = graphH / 10;
      // .. Draw row ..
      for (int j = graphY; j <= graphH + graphY; j += graphRow) {
        graphLine.setLine(graphX, j, graphX + graphW, j);
        big.draw(graphLine);
      }
      // .. Draw animated column movement ..
      int graphColumn = graphW / 15;
      if (columnInc == 0) {
        columnInc = graphColumn;
      }
      for (int j = graphX + columnInc; j < graphW + graphX; j += graphColumn) {
        graphLine.setLine(j, graphY, j, graphY + graphH);
        big.draw(graphLine);
      }
      --columnInc;
      // Plot memory usage by this memory pool.
      if (usedMem[npool] == null) {
        usedMem[npool] = new float[usageHistCount];
        ptNum[npool] = 0;
      }
      // save memory usage history.
      usedMem[npool][ptNum[npool]] = usedMemory;
      big.setColor(Color.yellow);
      int w1; // width of memory usage history.
      if (ptNum[npool] > graphW) {
        w1 = graphW;
      } else {
        w1 = ptNum[npool];
      }
      for (int j = graphX + graphW - w1, k = ptNum[npool] - w1; k < ptNum[npool]; k++, j++) {
        if (k != 0) {
          if (usedMem[npool][k] != usedMem[npool][k - 1]) {
            int h1 = (int) (graphY + graphH * ((totalMemory - usedMem[npool][k - 1]) / totalMemory));
            int h2 = (int) (graphY + graphH * ((totalMemory - usedMem[npool][k]) / totalMemory));
            big.drawLine(j - 1, h1, j, h2);
          } else {
            int h1 = (int) (graphY + graphH * ((totalMemory - usedMem[npool][k]) / totalMemory));
            big.fillRect(j, h1, 1, 1);
          }
        }
      }
      if (ptNum[npool] + 2 == usedMem[npool].length) {
        // throw out oldest point
        for (int j = 1; j < ptNum[npool]; j++) {
          usedMem[npool][j - 1] = usedMem[npool][j];
        }
        --ptNum[npool];
      } else {
        ptNum[npool]++;
      }
    }
    public void start() {
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.setName("MemoryMonitor");
      thread.start();
    }
    public synchronized void stop() {
      thread = null;
      notify();
    }
    public void run() {
      Thread me = Thread.currentThread();
      while (thread == me && !isShowing() || getSize().width == 0) {
        try {
          thread.sleep(500);
        } catch (InterruptedException e) {
          return;
        }
      }
      while (thread == me && isShowing()) {
        Dimension d = getSize();
        if (d.width != w || d.height != h) {
          w = d.width;
          h = d.height;
          bimg = (BufferedImage) createImage(w, h);
          big = bimg.createGraphics();
          big.setFont(font);
          FontMetrics fm = big.getFontMetrics(font);
          ascent = (int) fm.getAscent();
          descent = (int) fm.getDescent();
        }
        repaint();
        try {
          thread.sleep(sleepAmount);
        } catch (InterruptedException e) {
          break;
        }
        if (MemoryMonitor.dateStampCB.isSelected()) {
          System.out.println(new Date().toString() + " " + usedStr);
        }
      }
      thread = null;
    }
  }
  // Test thread to consume memory
  static class Memeater extends ClassLoader implements Runnable {
    Object y[];
    public Memeater() {
    }
    public void run() {
      y = new Object[10000000];
      int k = 0;
      while (true) {
        if (k == 5000000)
          k = 0;
        y[k++] = new Object();
        try {
          Thread.sleep(20);
        } catch (Exception x) {
        }
        // to consume perm gen storage
        try {
          // the classes are small so we load 10 at a time
          for (int i = 0; i < 10; i++) {
            loadNext();
          }
        } catch (ClassNotFoundException x) {
          // ignore exception
        }
      }
    }
    Class loadNext() throws ClassNotFoundException {
      // public class TestNNNNNN extends java.lang.Object{
      // public TestNNNNNN();
      // Code:
      // 0: aload_0
      // 1: invokespecial #1; //Method java/lang/Object."<init>":()V
      // 4: return
      // }
      int begin[] = { 0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x0a, 0x0a, 0x00, 0x03,
          0x00, 0x07, 0x07, 0x00, 0x08, 0x07, 0x00, 0x09, 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, 0x69,
          0x74, 0x3e, 0x01, 0x00, 0x03, 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43, 0x6f, 0x64, 0x65,
          0x0c, 0x00, 0x04, 0x00, 0x05, 0x01, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74 };
      int end[] = { 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f,
          0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x21, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00,
          0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x2a, 0xb7, 0x00, 0x01, 0xb1,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
      // TestNNNNNN
      String name = "Test" + Integer.toString(count++);
      byte value[];
      try {
        value = name.substring(4).getBytes("UTF-8");
      } catch (java.io.UnsupportedEncodingException x) {
        throw new Error();
      }
      // construct class file
      int len = begin.length + value.length + end.length;
      byte b[] = new byte[len];
      int i, pos = 0;
      for (i = 0; i < begin.length; i++) {
        b[pos++] = (byte) begin[i];
      }
      for (i = 0; i < value.length; i++) {
        b[pos++] = value[i];
      }
      for (i = 0; i < end.length; i++) {
        b[pos++] = (byte) end[i];
      }
      return defineClass(name, b, 0, b.length);
    }
    static int count = 100000;
  }
  public static void main(String s[]) {
    final MemoryMonitor demo = new MemoryMonitor();
    WindowListener l = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
      public void windowDeiconified(WindowEvent e) {
        demo.surf.start();
      }
      public void windowIconified(WindowEvent e) {
        demo.surf.stop();
      }
    };
    JFrame f = new JFrame("MemoryMonitor");
    f.addWindowListener(l);
    f.getContentPane().add("Center", demo);
    f.pack();
    f.setSize(new Dimension(400, 500));
    f.setVisible(true);
    demo.surf.start();
    Thread thr = new Thread(new Memeater());
    thr.start();
  }
}





Example of using the java.lang.management API to sort threads by CPU usage

   
/*
 * @(#)JTop.java  1.5 06/05/08
 *
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * @(#)JTop.java  1.5 06/05/08
 *
 * Example of using the java.lang.management API to sort threads
 * by CPU usage.
 *
 * JTop class can be run as a standalone application.
 * It first establishs a connection to a target VM specified
 * by the given hostname and port number where the JMX agent
 * to be connected.  It then polls for the thread information
 * and the CPU consumption of each thread to display every 2 
 * seconds.
 *
 * It is also used by JTopPlugin which is a JConsolePlugin
 * that can be used with JConsole (see README.txt). The JTop
 * GUI will be added as a JConsole tab by the JTop plugin.
 *
 * @see com.sun.tools.jconsole.JConsolePlugin
 *
 * @author Mandy Chung
 */
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.io.IOException;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.MalformedURLException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
/**
 * JTop is a JPanel to display thread"s name, CPU time, and its state in a
 * table.
 */
public class JTop extends JPanel {
  private MBeanServerConnection server;
  private ThreadMXBean tmbean;
  private MyTableModel tmodel;
  public JTop() {
    super(new GridLayout(1, 0));
    tmodel = new MyTableModel();
    JTable table = new JTable(tmodel);
    table.setPreferredScrollableViewportSize(new Dimension(500, 300));
    // Set the renderer to format Double
    table.setDefaultRenderer(Double.class, new DoubleRenderer());
    // Add some space
    table.setIntercellSpacing(new Dimension(6, 3));
    table.setRowHeight(table.getRowHeight() + 4);
    // Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(table);
    // Add the scroll pane to this panel.
    add(scrollPane);
  }
  // Set the MBeanServerConnection object for communicating
  // with the target VM
  public void setMBeanServerConnection(MBeanServerConnection mbs) {
    this.server = mbs;
    try {
      this.tmbean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class);
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (!tmbean.isThreadCpuTimeSupported()) {
      System.err.println("This VM does not support thread CPU time monitoring");
    } else {
      tmbean.setThreadCpuTimeEnabled(true);
    }
  }
  class MyTableModel extends AbstractTableModel {
    private String[] columnNames = { "ThreadName", "CPU(sec)", "State" };
    // List of all threads. The key of each entry is the CPU time
    // and its value is the ThreadInfo object with no stack trace.
    private List<Map.Entry<Long, ThreadInfo>> threadList = Collections.EMPTY_LIST;
    public MyTableModel() {
    }
    public int getColumnCount() {
      return columnNames.length;
    }
    public int getRowCount() {
      return threadList.size();
    }
    public String getColumnName(int col) {
      return columnNames[col];
    }
    public Object getValueAt(int row, int col) {
      Map.Entry<Long, ThreadInfo> me = threadList.get(row);
      switch (col) {
      case 0:
        // Column 0 shows the thread name
        return me.getValue().getThreadName();
      case 1:
        // Column 1 shows the CPU usage
        long ns = me.getKey().longValue();
        double sec = ns / 1000000000;
        return new Double(sec);
      case 2:
        // Column 2 shows the thread state
        return me.getValue().getThreadState();
      default:
        return null;
      }
    }
    public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
    }
    void setThreadList(List<Map.Entry<Long, ThreadInfo>> list) {
      threadList = list;
    }
  }
  /**
   * Get the thread list with CPU consumption and the ThreadInfo for each thread
   * sorted by the CPU time.
   */
  private List<Map.Entry<Long, ThreadInfo>> getThreadList() {
    // Get all threads and their ThreadInfo objects
    // with no stack trace
    long[] tids = tmbean.getAllThreadIds();
    ThreadInfo[] tinfos = tmbean.getThreadInfo(tids);
    // build a map with key = CPU time and value = ThreadInfo
    SortedMap<Long, ThreadInfo> map = new TreeMap<Long, ThreadInfo>();
    for (int i = 0; i < tids.length; i++) {
      long cpuTime = tmbean.getThreadCpuTime(tids[i]);
      // filter out threads that have been terminated
      if (cpuTime != -1 && tinfos[i] != null) {
        map.put(new Long(cpuTime), tinfos[i]);
      }
    }
    // build the thread list and sort it with CPU time
    // in decreasing order
    Set<Map.Entry<Long, ThreadInfo>> set = map.entrySet();
    List<Map.Entry<Long, ThreadInfo>> list = new ArrayList<Map.Entry<Long, ThreadInfo>>(set);
    Collections.reverse(list);
    return list;
  }
  /**
   * Format Double with 4 fraction digits
   */
  class DoubleRenderer extends DefaultTableCellRenderer {
    NumberFormat formatter;
    public DoubleRenderer() {
      super();
      setHorizontalAlignment(JLabel.RIGHT);
    }
    public void setValue(Object value) {
      if (formatter == null) {
        formatter = NumberFormat.getInstance();
        formatter.setMinimumFractionDigits(4);
      }
      setText((value == null) ? "" : formatter.format(value));
    }
  }
  // SwingWorker responsible for updating the GUI
  // 
  // It first gets the thread and CPU usage information as a
  // background task done by a worker thread so that
  // it will not block the event dispatcher thread.
  //
  // When the worker thread finishes, the event dispatcher
  // thread will invoke the done() method which will update
  // the UI.
  class Worker extends SwingWorker<List<Map.Entry<Long, ThreadInfo>>, Object> {
    private MyTableModel tmodel;
    Worker(MyTableModel tmodel) {
      this.tmodel = tmodel;
    }
    // Get the current thread info and CPU time
    public List<Map.Entry<Long, ThreadInfo>> doInBackground() {
      return getThreadList();
    }
    // fire table data changed to trigger GUI update
    // when doInBackground() is finished
    protected void done() {
      try {
        // Set table model with the new thread list
        tmodel.setThreadList(get());
        // refresh the table model
        tmodel.fireTableDataChanged();
      } catch (InterruptedException e) {
      } catch (ExecutionException e) {
      }
    }
  }
  // Return a new SwingWorker for UI update
  public SwingWorker<?, ?> newSwingWorker() {
    return new Worker(tmodel);
  }
  public static void main(String[] args) throws Exception {
    // Validate the input arguments
    if (args.length != 1) {
      usage();
    }
    String[] arg2 = args[0].split(":");
    if (arg2.length != 2) {
      usage();
    }
    String hostname = arg2[0];
    int port = -1;
    try {
      port = Integer.parseInt(arg2[1]);
    } catch (NumberFormatException x) {
      usage();
    }
    if (port < 0) {
      usage();
    }
    // Create the JTop Panel
    final JTop jtop = new JTop();
    // Set up the MBeanServerConnection to the target VM
    MBeanServerConnection server = connect(hostname, port);
    jtop.setMBeanServerConnection(server);
    // A timer task to update GUI per each interval
    TimerTask timerTask = new TimerTask() {
      public void run() {
        // Schedule the SwingWorker to update the GUI
        jtop.newSwingWorker().execute();
      }
    };
    // Create the standalone window with JTop panel
    // by the event dispatcher thread
    SwingUtilities.invokeAndWait(new Runnable() {
      public void run() {
        createAndShowGUI(jtop);
      }
    });
    // refresh every 2 seconds
    Timer timer = new Timer("JTop Sampling thread");
    timer.schedule(timerTask, 0, 2000);
  }
  // Establish a connection with the remote application
  //
  // You can modify the urlPath to the address of the JMX agent
  // of your application if it has a different URL.
  // 
  // You can also modify the following code to take
  // username and password for client authentication.
  private static MBeanServerConnection connect(String hostname, int port) {
    // Create an RMI connector client and connect it to
    // the RMI connector server
    String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
    MBeanServerConnection server = null;
    try {
      JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
      JMXConnector jmxc = JMXConnectorFactory.connect(url);
      server = jmxc.getMBeanServerConnection();
    } catch (MalformedURLException e) {
      // should not reach here
    } catch (IOException e) {
      System.err.println("\nCommunication error: " + e.getMessage());
      System.exit(1);
    }
    return server;
  }
  private static void usage() {
    System.out.println("Usage: java JTop <hostname>:<port>");
    System.exit(1);
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI(JPanel jtop) {
    // Create and set up the window.
    JFrame frame = new JFrame("JTop");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Create and set up the content pane.
    JComponent contentPane = (JComponent) frame.getContentPane();
    contentPane.add(jtop, BorderLayout.CENTER);
    contentPane.setOpaque(true); // content panes must be opaque
    contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
    frame.setContentPane(contentPane);
    // Display the window.
    frame.pack();
    frame.setVisible(true);
  }
}





MBeanTyperInvoker handles method invocations against the MBeanTyper target object and forwards them to the MBeanServer and ObjectName for invocation.

  
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
/**
 * MBeanTyper is a helper class that creates a typed-object from an MBean
 * ObjectName and a main interface class that the MBean implements. You can then
 * use the returned object (casted to the appropriate main interface class) with
 * the correct typed signatures instead of
 * <tt>mbeanserver.invoke(objectname,<sig>,etc.)</tt>.
 * <P>
 * Example usage: <BR>
 * <code><tt>
 *      MyInterfaceMBean mbean=(MyInterfaceMBean)MBeanTyper.typeMBean(server,new ObjectName(":type=MyBean"),MyInterfaceMBean.class);
 *      mbean.foobar();
 * </tt></code>
 * <P>
 * 
 * To turn debug on for this package, set the System property
 * <tt>vocalos.jmx.mbeantyper.debug</tt> to true.
 * 
 * @author 
 */
final class MBeanTyperInvoker implements java.lang.reflect.InvocationHandler {
  private final MBeanServer server;
  private final ObjectName mbean;
  private final Map signatureCache = Collections.synchronizedMap(new HashMap());
  MBeanTyperInvoker(MBeanServer server, ObjectName mbean) {
    this.server = server;
    this.mbean = mbean;
  }
  private boolean isJMXAttribute(Method m) {
    String name = m.getName();
    return (name.startsWith("get"));
  }
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (MBeanTyper.DEBUG) {
      System.err.println("  ++ method=" + method.getName() + ",args=" + args);
    }
    try {
      if (method.getDeclaringClass() == Object.class) {
        String name = method.getName();
        if (name.equals("hashCode")) {
          return new Integer(this.hashCode());
        } else if (name.equals("toString")) {
          return this.toString();
        } else if (name.equals("equals")) {
          // FIXME: this needs to be reviewed - we should be
          // smarter about this ...
          return new Boolean(equals(args[0]));
        }
      } else if (isJMXAttribute(method) && (args == null || args.length <= 0)) {
        String name = method.getName().substring(3);
        return server.getAttribute(mbean, name);
      }
      String sig[] = (String[]) signatureCache.get(method);
      if (sig == null) {
        // get the method signature from the method argument directly
        // vs. the arguments passed, since there may be primitives that
        // are wrapped as objects in the arguments
        Class _args[] = method.getParameterTypes();
        if (_args != null && _args.length > 0) {
          sig = new String[_args.length];
          for (int c = 0; c < sig.length; c++) {
            if (_args[c] != null) {
              sig[c] = _args[c].getName();
            }
          }
        } else {
          sig = new String[0];
        }
        signatureCache.put(method, sig);
      }
      return server.invoke(mbean, method.getName(), args, sig);
    } catch (Throwable t) {
      if (MBeanTyper.DEBUG) {
        t.printStackTrace();
      }
      if (t instanceof UndeclaredThrowableException) {
        UndeclaredThrowableException ut = (UndeclaredThrowableException) t;
        throw ut.getUndeclaredThrowable();
      } else if (t instanceof InvocationTargetException) {
        InvocationTargetException it = (InvocationTargetException) t;
        throw it.getTargetException();
      } else if (t instanceof MBeanException) {
        MBeanException me = (MBeanException) t;
        throw me.getTargetException();
      } else {
        throw t;
      }
    }
  }
}





Non-instantiable class that provides jmx utility methods

  
// Copyright 2007 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.logging.Logger;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;
/**
 * Non-instantiable class that provides jmx utility methods.
 */
public class Utilities {

  /**
   * Prints info about a bean to a {@link VarOutputSink}.
   * 
   * @param sink The {@link VarOutputSink} to which info will be sent
   * @param mbs The {@link MBeanServer} with respect to which the
   *          {@code objectName} is accessed
   * @param objectName The {@link ObjectName} that identifies this bean
   */
  public static void printMBeanInfo(VarOutputSink sink, MBeanServer mbs,
      ObjectName objectName) {
    MBeanInfo info = getMBeanInfoSafely(sink, mbs, objectName);
    if (info == null) { return; }
    sink.echo("\nCLASSNAME: \t" + info.getClassName());
    sink.echo("\nDESCRIPTION: \t" + info.getDescription());
    sink.echo("\nATTRIBUTES");
    MBeanAttributeInfo[] attrInfo = info.getAttributes();
    sink.printVariable("attrcount", Integer.toString(attrInfo.length));
    if (attrInfo.length > 0) {
      for (int i = 0; i < attrInfo.length; i++) {
        sink.echo(" ** NAME: \t" + attrInfo[i].getName());
        sink.echo("    DESCR: \t" + attrInfo[i].getDescription());
        sink
            .echo("    TYPE: \t" + attrInfo[i].getType() + "\tREAD: "
                + attrInfo[i].isReadable() + "\tWRITE: "
                + attrInfo[i].isWritable());
      }
    } else sink.echo(" ** No attributes **");
    sink.echo("\nCONSTRUCTORS");
    MBeanConstructorInfo[] constrInfo = info.getConstructors();
    for (int i = 0; i < constrInfo.length; i++) {
      sink.echo(" ** NAME: \t" + constrInfo[i].getName());
      sink.echo("    DESCR: \t" + constrInfo[i].getDescription());
      sink.echo("    PARAM: \t" + constrInfo[i].getSignature().length
          + " parameter(s)");
    }
    sink.echo("\nOPERATIONS");
    MBeanOperationInfo[] opInfo = info.getOperations();
    if (opInfo.length > 0) {
      for (int i = 0; i < opInfo.length; i++) {
        sink.echo(" ** NAME: \t" + opInfo[i].getName());
        sink.echo("    DESCR: \t" + opInfo[i].getDescription());
        sink.echo("    PARAM: \t" + opInfo[i].getSignature().length
            + " parameter(s)");
      }
    } else sink.echo(" ** No operations ** ");
    sink.echo("\nNOTIFICATIONS");
    MBeanNotificationInfo[] notifInfo = info.getNotifications();
    if (notifInfo.length > 0) {
      for (int i = 0; i < notifInfo.length; i++) {
        sink.echo(" ** NAME: \t" + notifInfo[i].getName());
        sink.echo("    DESCR: \t" + notifInfo[i].getDescription());
        String notifTypes[] = notifInfo[i].getNotifTypes();
        for (int j = 0; j < notifTypes.length; j++) {
          sink.echo("    TYPE: \t" + notifTypes[j]);
        }
      }
    } else sink.echo(" ** No notifications **");
  }
  private static MBeanInfo getMBeanInfoSafely(VarOutputSink sink,
      MBeanServer mbs, ObjectName objectName) {
    MBeanInfo info = null;
    try {
      info = mbs.getMBeanInfo(objectName);
    } catch (InstanceNotFoundException e) {
      sink.printVariable("ObjectName", "Not found");
    } catch (IntrospectionException e) {
      sink.printVariable("ObjectName", "IntrospectionException");
    } catch (ReflectionException e) {
      sink.printVariable("ObjectName", "ReflectionException");
    }
    return info;
  }
  /**
   * Prints bean attributes to a {@link VarOutputSink}.
   * 
   * @param sink The {@link VarOutputSink} to which attributes will be sent
   * @param mbs The {@link MBeanServer} with respect to which the
   *          {@code objectName} is accessed
   * @param objectName The {@link ObjectName} that identifies this bean
   */
  public static void printMBeanAttributes(VarOutputSink sink, MBeanServer mbs,
      ObjectName objectName) {
    MBeanInfo info = getMBeanInfoSafely(sink, mbs, objectName);
    if (info == null) {
      sink.printVariable(objectName.getCanonicalName(), "can"t fetch info");
      return;
    }
    MBeanAttributeInfo[] attrInfo = info.getAttributes();
    if (attrInfo.length > 0) {
      for (int i = 0; i < attrInfo.length; i++) {
        String attrName = attrInfo[i].getName();
        Object attrValue = null;
        String attrValueString = null;
        try {
          attrValue = mbs.getAttribute(objectName, attrName);
        } catch (AttributeNotFoundException e) {
          attrValueString = "AttributeNotFoundException";
        } catch (InstanceNotFoundException e) {
          attrValueString = "InstanceNotFoundException";
        } catch (MBeanException e) {
          attrValueString = "MBeanException";
        } catch (ReflectionException e) {
          attrValueString = "ReflectionException";
        }
        if (attrValueString == null) {
          attrValueString = attrValue.toString();
        }
        sink.printVariable(attrName, attrValueString);
      }
    }
  }
  /**
   * Helper interface defining output sinks used with
   * {@link Utilities#printMBeanInfo(com.google.enterprise.util.jmx.Utils.VarOutputSink, MBeanServer, ObjectName)}
   * and
   * {@link Utilities#printMBeanAttributes(com.google.enterprise.util.jmx.Utils.VarOutputSink, MBeanServer, ObjectName)}
   */
  public interface VarOutputSink {
    public void printVariable(String name, String value);
    public void echo(String string);
  }
  /**
   * Static {@link VarOutputSink} that uses {@link System#out}
   */
  public static final VarOutputSink SYSTEM_OUT_SINK = new PrintStreamVarOutputSink(
      System.out);
  public static class LoggerVarOutputSink implements VarOutputSink {
    private final Logger logger;
    public LoggerVarOutputSink(Logger logger) {
      this.logger = logger;
    }
    public void printVariable(String name, String value) {
      logger.info(name + " " + value);
    }
    public void echo(String string) {
      logger.info(string);
    }
  }
  public static class PrintWriterVarOutputSink implements VarOutputSink {
    private final PrintWriter printWriter;
    public PrintWriterVarOutputSink(PrintWriter printWriter) {
      this.printWriter = printWriter;
    }
    public void printVariable(String name, String value) {
      printWriter.print("  <b>");
      printWriter.print(name);
      printWriter.print("</b> ");
      printWriter.print(value);
      printWriter.println("<br>");
    }
    public void echo(String string) {
      printWriter.print(string);
    }
  }
  public static class PrintStreamVarOutputSink implements VarOutputSink {
    private final PrintStream printStream;
    public PrintStreamVarOutputSink(PrintStream printStream) {
      this.printStream = printStream;
    }
    public void printVariable(String name, String value) {
      printStream.print("  <b>");
      printStream.print(name);
      printStream.print("</b> ");
      printStream.print(value);
      printStream.println("<br>");
    }
    public void echo(String string) {
      printStream.print(string);
    }
  }
}





Performing deadlock detection programmatically within the application using the java.lang.management API

   
/*
 * @(#)Deadlock.java  1.5 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * @(#)Deadlock.java  1.5 05/11/17
 */
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.getThreadMXBean;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
import java.io.IOException;
import java.lang.management.LockInfo;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
/**
 * This Deadlock class demonstrates the capability of performing deadlock
 * detection programmatically within the application using the
 * java.lang.management API.
 * 
 * See ThreadMonitor.java for the use of java.lang.management.ThreadMXBean API.
 */
public class Deadlock {
  public static void main(String[] argv) {
    Deadlock dl = new Deadlock();
    // Now find deadlock
    ThreadMonitor monitor = new ThreadMonitor();
    boolean found = false;
    while (!found) {
      found = monitor.findDeadlock();
      try {
        Thread.sleep(500);
      } catch (InterruptedException e) {
        System.exit(1);
      }
    }
    System.out.println("\nPress <Enter> to exit this Deadlock program.\n");
    waitForEnterPressed();
  }
  private CyclicBarrier barrier = new CyclicBarrier(6);
  public Deadlock() {
    DeadlockThread[] dThreads = new DeadlockThread[6];
    Monitor a = new Monitor("a");
    Monitor b = new Monitor("b");
    Monitor c = new Monitor("c");
    dThreads[0] = new DeadlockThread("MThread-1", a, b);
    dThreads[1] = new DeadlockThread("MThread-2", b, c);
    dThreads[2] = new DeadlockThread("MThread-3", c, a);
    Lock d = new ReentrantLock();
    Lock e = new ReentrantLock();
    Lock f = new ReentrantLock();
    dThreads[3] = new DeadlockThread("SThread-4", d, e);
    dThreads[4] = new DeadlockThread("SThread-5", e, f);
    dThreads[5] = new DeadlockThread("SThread-6", f, d);
    // make them daemon threads so that the test will exit
    for (int i = 0; i < 6; i++) {
      dThreads[i].setDaemon(true);
      dThreads[i].start();
    }
  }
  class DeadlockThread extends Thread {
    private Lock lock1 = null;
    private Lock lock2 = null;
    private Monitor mon1 = null;
    private Monitor mon2 = null;
    private boolean useSync;
    DeadlockThread(String name, Lock lock1, Lock lock2) {
      super(name);
      this.lock1 = lock1;
      this.lock2 = lock2;
      this.useSync = true;
    }
    DeadlockThread(String name, Monitor mon1, Monitor mon2) {
      super(name);
      this.mon1 = mon1;
      this.mon2 = mon2;
      this.useSync = false;
    }
    public void run() {
      if (useSync) {
        syncLock();
      } else {
        monitorLock();
      }
    }
    private void syncLock() {
      lock1.lock();
      try {
        try {
          barrier.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
          System.exit(1);
        } catch (BrokenBarrierException e) {
          e.printStackTrace();
          System.exit(1);
        }
        goSyncDeadlock();
      } finally {
        lock1.unlock();
      }
    }
    private void goSyncDeadlock() {
      try {
        barrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
        System.exit(1);
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
        System.exit(1);
      }
      lock2.lock();
      throw new RuntimeException("should not reach here.");
    }
    private void monitorLock() {
      synchronized (mon1) {
        try {
          barrier.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
          System.exit(1);
        } catch (BrokenBarrierException e) {
          e.printStackTrace();
          System.exit(1);
        }
        goMonitorDeadlock();
      }
    }
    private void goMonitorDeadlock() {
      try {
        barrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
        System.exit(1);
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
        System.exit(1);
      }
      synchronized (mon2) {
        throw new RuntimeException(getName() + " should not reach here.");
      }
    }
  }
  class Monitor {
    String name;
    Monitor(String name) {
      this.name = name;
    }
  }
  private static void waitForEnterPressed() {
    try {
      boolean done = false;
      while (!done) {
        char ch = (char) System.in.read();
        if (ch < 0 || ch == "\n") {
          done = true;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(0);
    }
  }
}
/*
 * @(#)ThreadMonitor.java 1.6 05/12/22
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS
 * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
 * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */
/*
 * @(#)ThreadMonitor.java 1.6 05/12/22
 */
/**
 * Example of using the java.lang.management API to dump stack trace and to
 * perform deadlock detection.
 * 
 * @author Mandy Chung
 * @version %% 12/22/05
 */
class ThreadMonitor {
  private MBeanServerConnection server;
  private ThreadMXBean tmbean;
  private ObjectName objname;
  // default - JDK 6+ VM
  private String findDeadlocksMethodName = "findDeadlockedThreads";
  private boolean canDumpLocks = true;
  /**
   * Constructs a ThreadMonitor object to get thread information in a remote
   * JVM.
   */
  public ThreadMonitor(MBeanServerConnection server) throws IOException {
    this.server = server;
    this.tmbean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class);
    try {
      objname = new ObjectName(THREAD_MXBEAN_NAME);
    } catch (MalformedObjectNameException e) {
      // should not reach here
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    }
    parseMBeanInfo();
  }
  /**
   * Constructs a ThreadMonitor object to get thread information in the local
   * JVM.
   */
  public ThreadMonitor() {
    this.tmbean = getThreadMXBean();
  }
  /**
   * Prints the thread dump information to System.out.
   */
  public void threadDump() {
    if (canDumpLocks) {
      if (tmbean.isObjectMonitorUsageSupported() && tmbean.isSynchronizerUsageSupported()) {
        // Print lock info if both object monitor usage
        // and synchronizer usage are supported.
        // This sample code can be modified to handle if
        // either monitor usage or synchronizer usage is supported.
        dumpThreadInfoWithLocks();
      }
    } else {
      dumpThreadInfo();
    }
  }
  private void dumpThreadInfo() {
    System.out.println("Full Java thread dump");
    long[] tids = tmbean.getAllThreadIds();
    ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
    for (ThreadInfo ti : tinfos) {
      printThreadInfo(ti);
    }
  }
  /**
   * Prints the thread dump information with locks info to System.out.
   */
  private void dumpThreadInfoWithLocks() {
    System.out.println("Full Java thread dump with locks info");
    ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true);
    for (ThreadInfo ti : tinfos) {
      printThreadInfo(ti);
      LockInfo[] syncs = ti.getLockedSynchronizers();
      printLockInfo(syncs);
    }
    System.out.println();
  }
  private static String INDENT = "    ";
  private void printThreadInfo(ThreadInfo ti) {
    // print thread information
    printThread(ti);
    // print stack trace with locks
    StackTraceElement[] stacktrace = ti.getStackTrace();
    MonitorInfo[] monitors = ti.getLockedMonitors();
    for (int i = 0; i < stacktrace.length; i++) {
      StackTraceElement ste = stacktrace[i];
      System.out.println(INDENT + "at " + ste.toString());
      for (MonitorInfo mi : monitors) {
        if (mi.getLockedStackDepth() == i) {
          System.out.println(INDENT + "  - locked " + mi);
        }
      }
    }
    System.out.println();
  }
  private void printThread(ThreadInfo ti) {
    StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" + " Id="
        + ti.getThreadId() + " in " + ti.getThreadState());
    if (ti.getLockName() != null) {
      sb.append(" on lock=" + ti.getLockName());
    }
    if (ti.isSuspended()) {
      sb.append(" (suspended)");
    }
    if (ti.isInNative()) {
      sb.append(" (running in native)");
    }
    System.out.println(sb.toString());
    if (ti.getLockOwnerName() != null) {
      System.out.println(INDENT + " owned by " + ti.getLockOwnerName() + " Id="
          + ti.getLockOwnerId());
    }
  }
  private void printMonitorInfo(ThreadInfo ti, MonitorInfo[] monitors) {
    System.out.println(INDENT + "Locked monitors: count = " + monitors.length);
    for (MonitorInfo mi : monitors) {
      System.out.println(INDENT + "  - " + mi + " locked at ");
      System.out.println(INDENT + "      " + mi.getLockedStackDepth() + " "
          + mi.getLockedStackFrame());
    }
  }
  private void printLockInfo(LockInfo[] locks) {
    System.out.println(INDENT + "Locked synchronizers: count = " + locks.length);
    for (LockInfo li : locks) {
      System.out.println(INDENT + "  - " + li);
    }
    System.out.println();
  }
  /**
   * Checks if any threads are deadlocked. If any, print the thread dump
   * information.
   */
  public boolean findDeadlock() {
    long[] tids;
    if (findDeadlocksMethodName.equals("findDeadlockedThreads")
        && tmbean.isSynchronizerUsageSupported()) {
      tids = tmbean.findDeadlockedThreads();
      if (tids == null) {
        return false;
      }
      System.out.println("Deadlock found :-");
      ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
      for (ThreadInfo ti : infos) {
        printThreadInfo(ti);
        printLockInfo(ti.getLockedSynchronizers());
        System.out.println();
      }
    } else {
      tids = tmbean.findMonitorDeadlockedThreads();
      if (tids == null) {
        return false;
      }
      ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
      for (ThreadInfo ti : infos) {
        // print thread information
        printThreadInfo(ti);
      }
    }
    return true;
  }
  private void parseMBeanInfo() throws IOException {
    try {
      MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations();
      // look for findDeadlockedThreads operations;
      boolean found = false;
      for (MBeanOperationInfo op : mopis) {
        if (op.getName().equals(findDeadlocksMethodName)) {
          found = true;
          break;
        }
      }
      if (!found) {
        // if findDeadlockedThreads operation doesn"t exist,
        // the target VM is running on JDK 5 and details about
        // synchronizers and locks cannot be dumped.
        findDeadlocksMethodName = "findMonitorDeadlockedThreads";
        canDumpLocks = false;
      }
    } catch (IntrospectionException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    } catch (InstanceNotFoundException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    } catch (ReflectionException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    }
  }
}





Several utility functions for the JMX implementation

 
/*
 * Copyright (C) The MX4J Contributors.
 * All rights reserved.
 *
 * This software is distributed under the terms of the MX4J License version 1.0.
 * See the terms of the MX4J License in the documentation provided with this software.
 */

import java.lang.reflect.Array;
import java.lang.reflect.Method;
/**
 * Several utility functions for the JMX implementation
 *
 * @version $Revision: 1.18 $
 */
public class Utils
{
   /**
    * This methods load a class given the classloader and the name of the class, and work for
    * extended names of primitive types. <p>
    * If you try to do ClassLoader.loadClass("boolean") it barfs it cannot find the class,
    * so this method cope with this problem.
    */
   public static Class loadClass(ClassLoader loader, String name) throws ClassNotFoundException
   {
      if (name == null) throw new ClassNotFoundException("null");
      name = name.trim();
      if (name.equals("boolean"))
         return boolean.class;
      else if (name.equals("byte"))
         return byte.class;
      else if (name.equals("char"))
         return char.class;
      else if (name.equals("short"))
         return short.class;
      else if (name.equals("int"))
         return int.class;
      else if (name.equals("long"))
         return long.class;
      else if (name.equals("float"))
         return float.class;
      else if (name.equals("double"))
         return double.class;
      else if (name.equals("java.lang.String"))
         return String.class;
      else if (name.equals("java.lang.Object"))
         return Object.class;
      else if (name.startsWith("["))
      {
         // It"s an array, figure out how many dimensions
         int dimension = 0;
         while (name.charAt(dimension) == "[")
         {
            ++dimension;
         }
         char type = name.charAt(dimension);
         Class cls = null;
         switch (type)
         {
            case "Z":
               cls = boolean.class;
               break;
            case "B":
               cls = byte.class;
               break;
            case "C":
               cls = char.class;
               break;
            case "S":
               cls = short.class;
               break;
            case "I":
               cls = int.class;
               break;
            case "J":
               cls = long.class;
               break;
            case "F":
               cls = float.class;
               break;
            case "D":
               cls = double.class;
               break;
            case "L":
               // Strip the semicolon at the end
               String n = name.substring(dimension + 1, name.length() - 1);
               cls = loadClass(loader, n);
               break;
         }
         if (cls == null)
         {
            throw new ClassNotFoundException(name);
         }
         else
         {
            int[] dim = new int[dimension];
            return Array.newInstance(cls, dim).getClass();
         }
      }
      else
      {
         if (loader != null)
            return loader.loadClass(name);
         else
            return Class.forName(name, false, null);
      }
   }
   /**
    * Returns the classes whose names are specified by the <code>names</code> argument, loaded with the
    * specified classloader.
    */
   public static Class[] loadClasses(ClassLoader loader, String[] names) throws ClassNotFoundException
   {
      int n = names.length;
      Class[] cls = new Class[n];
      for (int i = 0; i < n; ++i)
      {
         String name = names[i];
         cls[i] = loadClass(loader, name);
      }
      return cls;
   }
   /**
    * Returns true is the given method is a JMX attribute getter method
    */
   public static boolean isAttributeGetter(Method m)
   {
      if (m == null) return false;
      String name = m.getName();
      Class retType = m.getReturnType();
      Class[] params = m.getParameterTypes();
      if (retType != Void.TYPE && params.length == 0)
      {
         if (name.startsWith("get") && name.length() > 3)
            return true;
         else if (name.startsWith("is") && name.length() > 2 && retType == Boolean.TYPE) return true;
      }
      return false;
   }
   /**
    * Returns true if the method is a JMX attribute setter method
    */
   public static boolean isAttributeSetter(Method m)
   {
      if (m == null) return false;
      String name = m.getName();
      Class retType = m.getReturnType();
      Class[] params = m.getParameterTypes();
      if (retType == Void.TYPE && params.length == 1 && name.startsWith("set") && name.length() > 3)
      {
         return true;
      }
      return false;
   }
   public static boolean wildcardMatch(String pattern, String string)
   {
      int stringLength = string.length();
      int stringIndex = 0;
      for (int patternIndex = 0; patternIndex < pattern.length(); ++patternIndex)
      {
         char c = pattern.charAt(patternIndex);
         if (c == "*")
         {
            // Recurse with the pattern without this "*" and the actual string, until
            // match is found or we inspected the whole string
            while (stringIndex < stringLength)
            {
               if (wildcardMatch(pattern.substring(patternIndex + 1), string.substring(stringIndex)))
               {
                  return true;
               }
               // No match found, try a shorter string, since we are matching "*"
               ++stringIndex;
            }
         }
         else if (c == "?")
         {
            // Increment the string index, since "?" match a single char in the string
            ++stringIndex;
            if (stringIndex > stringLength)
            {
               return false;
            }
         }
         else
         {
            // A normal character in the pattern, must match the one in the string
            if (stringIndex >= stringLength || c != string.charAt(stringIndex))
            {
               return false;
            }
            ++stringIndex;
         }
      }
      // I"ve inspected the whole pattern, but not the whole string
      return stringIndex == stringLength;
   }
   public static boolean arrayEquals(Object[] arr1, Object[] arr2)
   {
      if (arr1 == null && arr2 == null) return true;
      if (arr1 == null ^ arr2 == null) return false;
      if (!arr1.getClass().equals(arr2.getClass())) return false;
      if (arr1.length != arr2.length) return false;
      for (int i = 0; i < arr1.length; ++i)
      {
         Object obj1 = arr1[i];
         Object obj2 = arr2[i];
         if (obj1 == null ^ obj2 == null) return false;
         if (obj1 != null && !obj1.equals(obj2)) return false;
      }
      return true;
   }
   public static boolean arrayEquals(byte[] arr1, byte[] arr2)
   {
      if (arr1 == null && arr2 == null) return true;
      if (arr1 == null ^ arr2 == null) return false;
      if (!arr1.getClass().equals(arr2.getClass())) return false;
      if (arr1.length != arr2.length) return false;
      for (int i = 0; i < arr1.length; ++i)
      {
         byte b1 = arr1[i];
         byte b2 = arr2[i];
         if (b1 != b2) return false;
      }
      return true;
   }
   public static int arrayHashCode(Object[] arr)
   {
      int hash = 0;
      if (arr != null)
      {
         // Avoid that 2 arrays of length 0 but different classes return same hash
         hash ^= arr.getClass().hashCode();
         for (int i = 0; i < arr.length; ++i)
         {
            hash ^= arr[i] == null ? 0 : arr[i].hashCode();
         }
      }
      return hash;
   }
   public static int arrayHashCode(byte[] arr)
   {
      int hash = 0;
      if (arr != null)
      {
         // Avoid that 2 arrays of length 0 but different classes return same hash
         hash ^= arr.getClass().hashCode();
         for (int i = 0; i < arr.length; ++i)
         {
            hash ^= arr[i];
         }
      }
      return hash;
   }
   public static char[] arrayCopy(char[] chars)
   {
      if (chars == null) return null;
      char[] copy = new char[chars.length];
      System.arraycopy(chars, 0, copy, 0, chars.length);
      return copy;
   }
}





This FullThreadDump class demonstrates the capability to get a full thread dump and also detect deadlock remotely.

   
/*
 * @(#)FullThreadDump.java  1.5 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * @(#)FullThreadDump.java  1.5 05/11/17
 */
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.getThreadMXBean;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
import java.io.IOException;
import java.lang.management.LockInfo;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.MalformedURLException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
 * This FullThreadDump class demonstrates the capability to get a full thread
 * dump and also detect deadlock remotely.
 */
public class FullThreadDump {
  private MBeanServerConnection server;
  private JMXConnector jmxc;
  public FullThreadDump(String hostname, int port) {
    System.out.println("Connecting to " + hostname + ":" + port);
    // Create an RMI connector client and connect it to
    // the RMI connector server
    String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
    connect(urlPath);
  }
  public void dump() {
    try {
      ThreadMonitor monitor = new ThreadMonitor(server);
      monitor.threadDump();
      if (!monitor.findDeadlock()) {
        System.out.println("No deadlock found.");
      }
    } catch (IOException e) {
      System.err.println("\nCommunication error: " + e.getMessage());
      System.exit(1);
    }
  }
  /**
   * Connect to a JMX agent of a given URL.
   */
  private void connect(String urlPath) {
    try {
      JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
      this.jmxc = JMXConnectorFactory.connect(url);
      this.server = jmxc.getMBeanServerConnection();
    } catch (MalformedURLException e) {
      // should not reach here
    } catch (IOException e) {
      System.err.println("\nCommunication error: " + e.getMessage());
      System.exit(1);
    }
  }
  public static void main(String[] args) {
    if (args.length != 1) {
      usage();
    }
    String[] arg2 = args[0].split(":");
    if (arg2.length != 2) {
      usage();
    }
    String hostname = arg2[0];
    int port = -1;
    try {
      port = Integer.parseInt(arg2[1]);
    } catch (NumberFormatException x) {
      usage();
    }
    if (port < 0) {
      usage();
    }
    // get full thread dump and perform deadlock detection
    FullThreadDump ftd = new FullThreadDump(hostname, port);
    ftd.dump();
  }
  private static void usage() {
    System.out.println("Usage: java FullThreadDump <hostname>:<port>");
  }
}
/*
 * @(#)ThreadMonitor.java 1.6 05/12/22
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS
 * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
 * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */
/*
 * @(#)ThreadMonitor.java 1.6 05/12/22
 */
/**
 * Example of using the java.lang.management API to dump stack trace and to
 * perform deadlock detection.
 * 
 * @author Mandy Chung
 * @version %% 12/22/05
 */
class ThreadMonitor {
  private MBeanServerConnection server;
  private ThreadMXBean tmbean;
  private ObjectName objname;
  // default - JDK 6+ VM
  private String findDeadlocksMethodName = "findDeadlockedThreads";
  private boolean canDumpLocks = true;
  /**
   * Constructs a ThreadMonitor object to get thread information in a remote
   * JVM.
   */
  public ThreadMonitor(MBeanServerConnection server) throws IOException {
    this.server = server;
    this.tmbean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class);
    try {
      objname = new ObjectName(THREAD_MXBEAN_NAME);
    } catch (MalformedObjectNameException e) {
      // should not reach here
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    }
    parseMBeanInfo();
  }
  /**
   * Constructs a ThreadMonitor object to get thread information in the local
   * JVM.
   */
  public ThreadMonitor() {
    this.tmbean = getThreadMXBean();
  }
  /**
   * Prints the thread dump information to System.out.
   */
  public void threadDump() {
    if (canDumpLocks) {
      if (tmbean.isObjectMonitorUsageSupported() && tmbean.isSynchronizerUsageSupported()) {
        // Print lock info if both object monitor usage
        // and synchronizer usage are supported.
        // This sample code can be modified to handle if
        // either monitor usage or synchronizer usage is supported.
        dumpThreadInfoWithLocks();
      }
    } else {
      dumpThreadInfo();
    }
  }
  private void dumpThreadInfo() {
    System.out.println("Full Java thread dump");
    long[] tids = tmbean.getAllThreadIds();
    ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
    for (ThreadInfo ti : tinfos) {
      printThreadInfo(ti);
    }
  }
  /**
   * Prints the thread dump information with locks info to System.out.
   */
  private void dumpThreadInfoWithLocks() {
    System.out.println("Full Java thread dump with locks info");
    ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true);
    for (ThreadInfo ti : tinfos) {
      printThreadInfo(ti);
      LockInfo[] syncs = ti.getLockedSynchronizers();
      printLockInfo(syncs);
    }
    System.out.println();
  }
  private static String INDENT = "    ";
  private void printThreadInfo(ThreadInfo ti) {
    // print thread information
    printThread(ti);
    // print stack trace with locks
    StackTraceElement[] stacktrace = ti.getStackTrace();
    MonitorInfo[] monitors = ti.getLockedMonitors();
    for (int i = 0; i < stacktrace.length; i++) {
      StackTraceElement ste = stacktrace[i];
      System.out.println(INDENT + "at " + ste.toString());
      for (MonitorInfo mi : monitors) {
        if (mi.getLockedStackDepth() == i) {
          System.out.println(INDENT + "  - locked " + mi);
        }
      }
    }
    System.out.println();
  }
  private void printThread(ThreadInfo ti) {
    StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" + " Id="
        + ti.getThreadId() + " in " + ti.getThreadState());
    if (ti.getLockName() != null) {
      sb.append(" on lock=" + ti.getLockName());
    }
    if (ti.isSuspended()) {
      sb.append(" (suspended)");
    }
    if (ti.isInNative()) {
      sb.append(" (running in native)");
    }
    System.out.println(sb.toString());
    if (ti.getLockOwnerName() != null) {
      System.out.println(INDENT + " owned by " + ti.getLockOwnerName() + " Id="
          + ti.getLockOwnerId());
    }
  }
  private void printMonitorInfo(ThreadInfo ti, MonitorInfo[] monitors) {
    System.out.println(INDENT + "Locked monitors: count = " + monitors.length);
    for (MonitorInfo mi : monitors) {
      System.out.println(INDENT + "  - " + mi + " locked at ");
      System.out.println(INDENT + "      " + mi.getLockedStackDepth() + " "
          + mi.getLockedStackFrame());
    }
  }
  private void printLockInfo(LockInfo[] locks) {
    System.out.println(INDENT + "Locked synchronizers: count = " + locks.length);
    for (LockInfo li : locks) {
      System.out.println(INDENT + "  - " + li);
    }
    System.out.println();
  }
  /**
   * Checks if any threads are deadlocked. If any, print the thread dump
   * information.
   */
  public boolean findDeadlock() {
    long[] tids;
    if (findDeadlocksMethodName.equals("findDeadlockedThreads")
        && tmbean.isSynchronizerUsageSupported()) {
      tids = tmbean.findDeadlockedThreads();
      if (tids == null) {
        return false;
      }
      System.out.println("Deadlock found :-");
      ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
      for (ThreadInfo ti : infos) {
        printThreadInfo(ti);
        printLockInfo(ti.getLockedSynchronizers());
        System.out.println();
      }
    } else {
      tids = tmbean.findMonitorDeadlockedThreads();
      if (tids == null) {
        return false;
      }
      ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
      for (ThreadInfo ti : infos) {
        // print thread information
        printThreadInfo(ti);
      }
    }
    return true;
  }
  private void parseMBeanInfo() throws IOException {
    try {
      MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations();
      // look for findDeadlockedThreads operations;
      boolean found = false;
      for (MBeanOperationInfo op : mopis) {
        if (op.getName().equals(findDeadlocksMethodName)) {
          found = true;
          break;
        }
      }
      if (!found) {
        // if findDeadlockedThreads operation doesn"t exist,
        // the target VM is running on JDK 5 and details about
        // synchronizers and locks cannot be dumped.
        findDeadlocksMethodName = "findMonitorDeadlockedThreads";
        canDumpLocks = false;
      }
    } catch (IntrospectionException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    } catch (InstanceNotFoundException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    } catch (ReflectionException e) {
      InternalError ie = new InternalError(e.getMessage());
      ie.initCause(e);
      throw ie;
    }
  }
}





This VerboseGC class demonstrates the capability to get the garbage collection statistics and memory usage remotely

   
/*
 * @(#)VerboseGC.java 1.4 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * @(#)VerboseGC.java 1.4 05/11/17
 */
import static java.lang.management.ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE;
import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE;
import static java.lang.management.ManagementFactory.RUNTIME_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.getGarbageCollectorMXBeans;
import static java.lang.management.ManagementFactory.getMemoryMXBean;
import static java.lang.management.ManagementFactory.getMemoryPoolMXBeans;
import static java.lang.management.ManagementFactory.getRuntimeMXBean;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
import java.io.IOException;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
 * This VerboseGC class demonstrates the capability to get the garbage
 * collection statistics and memory usage remotely.
 */
public class VerboseGC {
  private MBeanServerConnection server;
  private JMXConnector jmxc;
  public VerboseGC(String hostname, int port) {
    System.out.println("Connecting to " + hostname + ":" + port);
    // Create an RMI connector client and connect it to
    // the RMI connector server
    String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
    connect(urlPath);
  }
  public void dump(long interval, long samples) {
    try {
      PrintGCStat pstat = new PrintGCStat(server);
      for (int i = 0; i < samples; i++) {
        pstat.printVerboseGc();
        try {
          Thread.sleep(interval);
        } catch (InterruptedException e) {
          System.exit(1);
        }
      }
    } catch (IOException e) {
      System.err.println("\nCommunication error: " + e.getMessage());
      System.exit(1);
    }
  }
  /**
   * Connect to a JMX agent of a given URL.
   */
  private void connect(String urlPath) {
    try {
      JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
      this.jmxc = JMXConnectorFactory.connect(url);
      this.server = jmxc.getMBeanServerConnection();
    } catch (MalformedURLException e) {
      // should not reach here
    } catch (IOException e) {
      System.err.println("\nCommunication error: " + e.getMessage());
      System.exit(1);
    }
  }
  public static void main(String[] args) {
    if (args.length < 1) {
      usage();
    }
    String hostname = "";
    int port = -1;
    long interval = 5000; // default is 5 second interval
    long mins = 5;
    for (int argIndex = 0; argIndex < args.length; argIndex++) {
      String arg = args[argIndex];
      if (args[argIndex].startsWith("-")) {
        if (arg.equals("-h") || arg.equals("-help") || arg.equals("-?")) {
          usage();
        } else if (arg.startsWith("-interval=")) {
          try {
            interval = Integer.parseInt(arg.substring(10)) * 1000;
          } catch (NumberFormatException ex) {
            usage();
          }
        } else if (arg.startsWith("-duration=")) {
          try {
            mins = Integer.parseInt(arg.substring(10));
          } catch (NumberFormatException ex) {
            usage();
          }
        } else {
          // Unknown switch
          System.err.println("Unrecognized option: " + arg);
          usage();
        }
      } else {
        String[] arg2 = arg.split(":");
        if (arg2.length != 2) {
          usage();
        }
        hostname = arg2[0];
        try {
          port = Integer.parseInt(arg2[1]);
        } catch (NumberFormatException x) {
          usage();
        }
        if (port < 0) {
          usage();
        }
      }
    }
    // get full thread dump and perform deadlock detection
    VerboseGC vgc = new VerboseGC(hostname, port);
    long samples = (mins * 60 * 1000) / interval;
    vgc.dump(interval, samples);
  }
  private static void usage() {
    System.out.print("Usage: java VerboseGC <hostname>:<port> ");
    System.out.println(" [-interval=seconds] [-duration=minutes]");
  }
}
/*
 * @(#)PrintGCStat.java 1.4 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS
 * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
 * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */
/*
 * @(#)PrintGCStat.java 1.4 05/11/17
 */
/**
 * Example of using the java.lang.management API to monitor the memory usage and
 * garbage collection statistics.
 * 
 * @author Mandy Chung
 * @version %% 11/17/05
 */
class PrintGCStat {
  private RuntimeMXBean rmbean;
  private MemoryMXBean mmbean;
  private List<MemoryPoolMXBean> pools;
  private List<GarbageCollectorMXBean> gcmbeans;
  /**
   * Constructs a PrintGCStat object to monitor a remote JVM.
   */
  public PrintGCStat(MBeanServerConnection server) throws IOException {
    // Create the platform mxbean proxies
    this.rmbean = newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
    this.mmbean = newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME, MemoryMXBean.class);
    ObjectName poolName = null;
    ObjectName gcName = null;
    try {
      poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",*");
      gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");
    } catch (MalformedObjectNameException e) {
      // should not reach here
      assert (false);
    }
    Set mbeans = server.queryNames(poolName, null);
    if (mbeans != null) {
      pools = new ArrayList<MemoryPoolMXBean>();
      Iterator iterator = mbeans.iterator();
      while (iterator.hasNext()) {
        ObjectName objName = (ObjectName) iterator.next();
        MemoryPoolMXBean p = newPlatformMXBeanProxy(server, objName.getCanonicalName(),
            MemoryPoolMXBean.class);
        pools.add(p);
      }
    }
    mbeans = server.queryNames(gcName, null);
    if (mbeans != null) {
      gcmbeans = new ArrayList<GarbageCollectorMXBean>();
      Iterator iterator = mbeans.iterator();
      while (iterator.hasNext()) {
        ObjectName objName = (ObjectName) iterator.next();
        GarbageCollectorMXBean gc = newPlatformMXBeanProxy(server, objName.getCanonicalName(),
            GarbageCollectorMXBean.class);
        gcmbeans.add(gc);
      }
    }
  }
  /**
   * Constructs a PrintGCStat object to monitor the local JVM.
   */
  public PrintGCStat() {
    // Obtain the platform mxbean instances for the running JVM.
    this.rmbean = getRuntimeMXBean();
    this.mmbean = getMemoryMXBean();
    this.pools = getMemoryPoolMXBeans();
    this.gcmbeans = getGarbageCollectorMXBeans();
  }
  /**
   * Prints the verbose GC log to System.out to list the memory usage of all
   * memory pools as well as the GC statistics.
   */
  public void printVerboseGc() {
    System.out.print("Uptime: " + formatMillis(rmbean.getUptime()));
    for (GarbageCollectorMXBean gc : gcmbeans) {
      System.out.print(" [" + gc.getName() + ": ");
      System.out.print("Count=" + gc.getCollectionCount());
      System.out.print(" GCTime=" + formatMillis(gc.getCollectionTime()));
      System.out.print("]");
    }
    System.out.println();
    for (MemoryPoolMXBean p : pools) {
      System.out.print("  [" + p.getName() + ":");
      MemoryUsage u = p.getUsage();
      System.out.print(" Used=" + formatBytes(u.getUsed()));
      System.out.print(" Committed=" + formatBytes(u.getCommitted()));
      System.out.println("]");
    }
  }
  private String formatMillis(long ms) {
    return String.format("%.4fsec", ms / (double) 1000);
  }
  private String formatBytes(long bytes) {
    long kb = bytes;
    if (bytes > 0) {
      kb = bytes / 1024;
    }
    return kb + "K";
  }
}