summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java')
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java
new file mode 100644
index 0000000..85960ed
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java
@@ -0,0 +1,183 @@
+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;
+ }
+ }
+
+}