Visualizing Threads in the JConsole

While reading Beginning Java SE 6 Platform: From Novice to Professional, I discovered for the first time that the JConsole is pluggable, since Java SE 6. That's maybe not exactly news, if you're a friend of JConsole and have followed its adventures over the past years. Personally, I'm more interested in JConsole's pluggability than JConsole itself.

The JDK provides a set of demos, some of which are helpful in understanding how plugins work in relation to JConsole. Go to demo/management in the JDK's installation folder and you'll find them. Especially JTop is helpful in showing how a new panel can be added to the JConsole. The panel is simply a JPanel. In addition to the JPanel, you need a class that extend JConsolePlugin, which uses its getTabs method to retrieve the JPanel. From page 245 of the abovementioned book, you get a brilliant exposition of everything related to the JConsole's pluggability. (Here's hoping that the same author will get to write the book on Java SE 7.) Mandy Chung's blog, which is also referenced in the book above, is also great in its discussion of the JConsole and its pluggability.

In my first experiment, I added a web browser to JConsole. That was kind of fun, though I wasn't interacting with any of the data provided by the JConsole. Here is my second experiment, which is more interesting, providing a visual thread window in the JConsole:

The visual part of the above JConsole plugin is provided by the NetBeans Visual Library API. Whenever I detect a thread name, I create a new node on the canvas. When I detect a new state or a new ID, I create a pin, which is the info below the thread name in the screenshot above. Here's the code for that part:

void setThreadList(List<Entry<Long, ThreadInfo>> list, DemoGraphScene scene, MBeanServerConnection server) {
    threadList = list;
    for (int i = 0; i < threadList.size(); i++) {
        String text = threadList.get(i).getValue().getThreadName();
        String state = threadList.get(i).getValue().getThreadState().name();
        Long threadId = threadList.get(i).getValue().getThreadId();
        createNode(scene, (int) (300), (int) (300), text, "Value", null);
        createPin(this, text, text + ":" + state, "State: " + state, null);
        createPin(this, text, text + ":" + threadId, "Id: " + threadId, null);

Here are the three methods used for creating the nodes and pins, as well as the movement which positions the nodes on the canvas:

private String createNode(DemoGraphScene scene, int x, int y, String name, String type, java.util.List<Image> glyphs) {
    String nodeID = name;
    if (!scene.getNodes().contains(nodeID)) {
        VMDNodeWidget widget = (VMDNodeWidget) scene.addNode(nodeID);
        widget.setPreferredLocation(new Point(x, y));
        widget.setNodeProperties(null, name, type, glyphs);
    return nodeID;

private static void createPin(DemoGraphScene scene, String nodeID, String pinID, String name, String type) {
    if (!scene.getPins().contains(pinID)) {
        ((VMDPinWidget) scene.addPin(nodeID, pinID)).setProperties(name, null);

private void moveTo(Point point) {
    int index = 0;
    for (String node : getNodes()) {
        getSceneAnimator().animatePreferredLocation(findWidget(node), point != null ? point : new Point(100, ++index \* 100));

All of the above is in a class that extends VMDGraphScene. And that's most of the plugin, the rest is pretty much the same as the JTop demo plugin that you can find in the JDK's installation folder. It's pretty cool that one can now extend the JConsole, gives you a lot of room to manouevre.

Once you've created a JAR that contains your plugin, you need to start the JConsole together with the --pluginpath command line argument. And the value of the argument is the location of the JAR. I normally start up the JConsole from an Ant script that overrides the application's Run target. The application isn't able to run anyway, since it is a plugin, so the Run target is useless. So, I've given it some purpose by using it to start JConsole, together with my plugin:

    <target name="run">
        <exec dir="../../../bin" executable="jconsole">
            <arg value="-pluginpath"/>
            <arg value="..demo/management/VMDDemoPlugin/dist/VMDDemoPlugin.jar"/>

Then, because you've created a META-INF/services folder, as shown in the JTop sample, and because of the abovementioned class that extends JConsolePlugin, a new tab is added to the JConsole, as defined by your JPanel.


Post a Comment:
  • HTML Syntax: NOT allowed

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.


« July 2016