package org.simpleframework.http.core;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
public class ThreadDumper extends Thread {
private static String INDENT = " ";
private CountDownLatch latch;
private volatile boolean dead;
private int wait;
public ThreadDumper() {
this(10000);
}
public ThreadDumper(int wait) {
this.latch = new CountDownLatch(1);
this.wait = wait;
}
public void waitUntilStarted() throws InterruptedException{
latch.await();
}
public void kill(){
try {
Thread.sleep(1000);
dead = true;
dumpThreadInfo();
}catch(Exception e){
e.printStackTrace();
}
}
public void run() {
while(!dead) {
try{
latch.countDown();
dumpThreadInfo();
findDeadlock();
Thread.sleep(wait);
}catch(Exception e){
e.printStackTrace();
}
}
}
public String dumpThreads() {
Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
return generateDump(stackTraces);
}
public static String dumpCurrentThread() {
Thread currentThread = Thread.currentThread();
StackTraceElement[] stackTrace = currentThread.getStackTrace();
Map<Thread, StackTraceElement[]> stackTraces = Collections.singletonMap(currentThread, stackTrace);
return generateDump(stackTraces);
}
private static String generateDump(Map<Thread, StackTraceElement[]> stackTraces) {
StringBuilder builder = new StringBuilder();
builder.append("<pre>");
builder.append("<b>Full Java thread dump</b>");
builder.append("\n");
Set<Thread> threads = stackTraces.keySet();
for (Thread thread : threads) {
StackTraceElement[] stackElements = stackTraces.get(thread);
generateDescription(thread, builder);
generateStackFrames(stackElements, builder);
}
builder.append("</pre>");
return builder.toString();
}
private static void generateStackFrames(StackTraceElement[] stackElements, StringBuilder builder) {
for (StackTraceElement stackTraceElement : stackElements) {
builder.append(" at ");
builder.append(stackTraceElement);
builder.append("\n");
}
}
private static void generateDescription(Thread thread, StringBuilder builder) {
Thread.State threadState = thread.getState();
String threadName = thread.getName();
long threadId = thread.getId();
builder.append("\n");
builder.append("<b>");
builder.append(threadName);
builder.append("</b> Id=");
builder.append(threadId);
builder.append(" in ");
builder.append(threadState);
builder.append("\n");
}
/**
* Prints the thread dump information to System.out.
*/
public static void dumpThreadInfo(){
System.out.println(getThreadInfo());
}
public static String getThreadInfo() {
ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
long[] tids = tmbean.getAllThreadIds();
ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
StringWriter str = new StringWriter();
PrintWriter log = new PrintWriter(str);
log.println("Full Java thread dump");
for (ThreadInfo ti : tinfos) {
printThreadInfo(ti, log);
}
log.flush();
return str.toString();
}
private static void printThreadInfo(ThreadInfo ti, PrintWriter log) {
if(ti != null) {
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)");
}
log.println(sb.toString());
if (ti.getLockOwnerName() != null) {
log.println(INDENT + " owned by " + ti.getLockOwnerName() +
" Id=" + ti.getLockOwnerId());
}
for (StackTraceElement ste : ti.getStackTrace()) {
log.println(INDENT + "at " + ste.toString());
}
log.println();
}
}
/**
* Checks if any threads are deadlocked. If any, print
* the thread dump information.
*/
public static boolean findDeadlock() {
ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
long[] tids = tmbean.findMonitorDeadlockedThreads();
if (tids == null) {
return false;
} else {
StringWriter str = new StringWriter();
PrintWriter log = new PrintWriter(str);
tids = tmbean.getAllThreadIds();
System.out.println("Deadlock found :-");
ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
for (ThreadInfo ti : tinfos) {
printThreadInfo(ti, log);
}
log.flush();
System.out.println(str.toString());
return true;
}
}
}