Thread Utils

Some time back I posted some memory info utilities. Since then I’ve had it in the back of my head to try and get a programmatic dump of the thread stack traces like you can get with Ctrl-Break (on Windows) or Ctrl-\ (on Linux) or kill -3 pid. (SIGQUIT)

These are useful to seeing why programs are hanging and this particular thread dump will also tell you information about deadlocks. It’s been a critical tool for me since it was introduced oh so many years ago.

However, in many cases it is inconvenient to manually trigger such a dump. For one, I’ve never been able to figure out how to do from the SDK and for another, when running as a launch4j executable you don’t even have the console anymore. The biggest thing is that I wanted something that users could trigger with a special hot-key combination right from inside the game.

In the midst of some threading issue, it’s nice to collect as much data as possible before you kill the program for real and lose all of that once in a lifetime state.

…and so I finally got off my rear and figured this out. The results are this ThreadUtils class.

[java]
package util;

import java.lang.management.;
import java.util.
;

public class ThreadUtils {
public static void safeSleep( long ms ) {
try {
Thread.sleep(ms);
} catch( InterruptedException e ) {
throw new RuntimeException( “Thread interrupted”, e );
}
}

public static String getThreadDumpString() {
    ThreadMXBean threads = ManagementFactory.getThreadMXBean(); 

    StringBuilder sb = new StringBuilder();
    
    sb.append( String.format("Thread dump at: %1$tF %1$tT", new java.util.Date()) );
    sb.append( "\n\n" );    

    long[] deadLockedArray = threads.findDeadlockedThreads();
    Set<Long> deadlocks = new HashSet<Long>();
    if( deadLockedArray != null ) {
        for( long i : deadLockedArray ) {
            deadlocks.add(i);
        }
    }

    // Build a TID map for looking up more specific thread
    // information than provided by ThreadInfo
    Map<Long, Thread> threadMap = new HashMap<Long, Thread>();
    for( Thread t : Thread.getAllStackTraces().keySet() ) {
        threadMap.put( t.getId(), t );
    } 
      
    // This only works in 1.6+... but I think that's ok
    ThreadInfo[] infos = threads.dumpAllThreads(true, true);
    for( ThreadInfo info : infos ) {
        StringBuilder threadMetaData = new StringBuilder();
        Thread thread = threadMap.get(info.getThreadId());            
        if( thread != null ) {
            threadMetaData.append("(");
            threadMetaData.append(thread.isDaemon() ? "daemon " : "");
            threadMetaData.append(thread.isInterrupted() ? "interrupted " : "");
            threadMetaData.append("prio=" + thread.getPriority());
            threadMetaData.append(")");                
        }  
        String s = info.toString().trim();
        
        // Inject the meta-data after the ID... Presumes a 
        // certain format but it's low priority information.            
        s = s.replaceFirst( "Id=\\d+", "$0 " + threadMetaData );
        sb.append( s );
        sb.append( "\n" );

        if( deadlocks.contains(info.getThreadId()) ) {
            sb.append( " ** Deadlocked **" );
            sb.append( "\n" );
        }
            
        sb.append( "\n" );
    }
    return sb.toString();    
}

public static void dumpThreadInfo() {
    System.out.println( getThreadDumpString() );            
}

}
[/java]

On Oracle’s JDK, this prints a nice set of info. Apparently the ThreadInfo.toString() is implementation specific so the output may suck on other non-Oracle JDKs… we’ll just have to see, I guess. In the standard JDK it’s nice because it smartly combines a lot of info in a nice readable form that would take a bunch of logic to duplicate.

As a test, you can force a deadlock and then dump the threads:
[java]
public static void main( String… args ) throws Exception {
final Object obj1 = new Object();
final Object obj2 = new Object();
Thread test1 = new Thread( “Test1” ) {
public void run() {
synchronized( obj1 ) {
ThreadUtils.safeSleep(1000);
synchronized( obj2 ) {
while( true ) {
ThreadUtils.safeSleep(10);
}
}
}
}
};

    Thread test2 = new Thread( "Test2" ) {
            public void run() {
                synchronized( obj2 ) {
                    ThreadUtils.safeSleep(1000);
                    synchronized( obj1 ) {
                        while( true ) {
                            ThreadUtils.safeSleep(10);
                        }
                    }
                }
            }
        };

    test1.start();
    test2.start();       

    Thread.sleep(2000);

    ThreadUtils.dumpThreadInfo();
    
    System.exit(0);
}

[/java]

Maybe someone finds it useful. For tracking down random or rare thread/lock/resource deadlocks it can be a life saver to get this information.

Edit: note that because of the specific method I use on the mbean, this is Java 1.6 or higher only.

5 Likes

For the record, the thread dump for putting that main right in the ThreadUtils class to test looks like this:

[java]
Thread dump at: 2013-06-23 03:24:07

“Test2” Id=9 (prio=5) BLOCKED on java.lang.Object@186c730 owned by “Test1” Id=8
at mythruna.util.ThreadUtils$2.run(ThreadUtils.java:64)
- blocked on java.lang.Object@186c730
- locked java.lang.Object@1da669c
** Deadlocked **

“Test1” Id=8 (prio=5) BLOCKED on java.lang.Object@1da669c owned by “Test2” Id=9
at mythruna.util.ThreadUtils$1.run(ThreadUtils.java:47)
- blocked on java.lang.Object@1da669c
- locked java.lang.Object@186c730
** Deadlocked **

“Attach Listener” Id=5 (daemon prio=5) RUNNABLE

“Signal Dispatcher” Id=4 (daemon prio=9) RUNNABLE

“Finalizer” Id=3 (daemon prio=8) WAITING on java.lang.ref.ReferenceQueue$Lock@17f242c
at java.lang.Object.wait(Native Method)
- waiting on java.lang.ref.ReferenceQueue$Lock@17f242c
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

“Reference Handler” Id=2 (daemon prio=10) WAITING on java.lang.ref.Reference$Lock@1fd5e2
at java.lang.Object.wait(Native Method)
- waiting on java.lang.ref.Reference$Lock@1fd5e2
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)

“main” Id=1 (prio=5) RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.dumpAllThreads(ThreadImpl.java:446)
at mythruna.util.ThreadUtils.getThreadDumpString(ThreadUtils.java:106)
at mythruna.util.ThreadUtils.dumpThreadInfo(ThreadUtils.java:140)
at mythruna.util.ThreadUtils.main(ThreadUtils.java:76)
[/java]

<cite>@pspeed said:</cite> However, in many cases it is inconvenient to manually trigger such a dump. For one, I've never been able to figure out how to do from the SDK and for another, when running as a launch4j executable you don't even have the console anymore.

You can trigger thread dumps from jvisualvm, good tool to have when you are e.g. running a headless game server.

I didn’t understand the purpose of this?

[java] public static void safeSleep( long ms ) {
try {
Thread.sleep(ms);
} catch( InterruptedException e ) {
throw new RuntimeException( “Thread interrupted”, e );
}
}[/java]

Wrapping in a runtime exception and not resetting the interrupted-flag doesn’t seem very safe :slight_smile:

@jmaasing said: You can trigger thread dumps from jvisualvm, good tool to have when you are e.g. running a headless game server.

I didn’t understand the purpose of this?

[java] public static void safeSleep( long ms ) {
try {
Thread.sleep(ms);
} catch( InterruptedException e ) {
throw new RuntimeException( “Thread interrupted”, e );
}
}[/java]

Wrapping in a runtime exception and not resetting the interrupted-flag doesn’t seem very safe :slight_smile:

The thread will die anyway. I don’t want to prevent the thread from dying, I just don’t want to catch a useless exception just to sleep.

Updated the code slightly to avoid an NPE if the deadlocked array is null.