001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.lang; 018 019import java.lang.management.ManagementFactory; 020import java.lang.management.RuntimeMXBean; 021import java.util.HashMap; 022import java.util.Map; 023import java.util.Map.Entry; 024 025import org.apache.wicket.util.string.interpolator.MapVariableInterpolator; 026import org.slf4j.Logger; 027 028/** 029 * A utility class for dealing with {@link Thread}s. 030 */ 031public class Threads 032{ 033 034 private static final String FORMAT = "\"${name}\"${isDaemon} prio=${priority} tid=${threadIdDec} state=${state} "; 035 036 private Threads() 037 { 038 } 039 040 /** 041 * Creates a dump of all the threads' state and stack traces similar to what JVM produces when 042 * signal SIGQUIT is send to the process on Unix machine. 043 * <p> 044 * Note: This is a best effort to dump as much information as possible because the Java API 045 * doesn't provide means to get all the information that is produced by jstack program for 046 * example. 047 * </p> 048 * 049 * @param logger 050 * the logger where the collected information will be written 051 */ 052 public static void dumpAllThreads(Logger logger) 053 { 054 Args.notNull(logger, "logger"); 055 if (!logger.isWarnEnabled()) 056 { 057 return; 058 } 059 060 RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); 061 062 StringBuilder dump = new StringBuilder(); 063 064 dump.append("Full thread dump ") 065 .append(runtimeMXBean.getVmName()) 066 .append('(') 067 .append(runtimeMXBean.getVmVersion()) 068 .append(')'); 069 logger.warn(dump.toString()); 070 071 Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces(); 072 for (Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) 073 { 074 dumpSingleThread(logger, entry.getKey(), entry.getValue()); 075 } 076 } 077 078 /** 079 * Creates a dump of the threads' state and stack traces similar to the one that the JVM 080 * produces when signal SIGQUIT is send to the process on Unix machine. 081 * <p> 082 * Note: This is a best effort to dump as much information as possible because the Java API 083 * doesn't provide means to get all the information that is produced by jstack program for 084 * example. 085 * </p> 086 * 087 * @param logger 088 * the logger where the collected information will be written 089 * @param thread 090 * the thread to dump 091 */ 092 public static void dumpSingleThread(Logger logger, Thread thread) 093 { 094 Args.notNull(logger, "logger"); 095 if (!logger.isWarnEnabled()) 096 { 097 return; 098 } 099 100 dumpSingleThread(logger, thread, thread.getStackTrace()); 101 } 102 103 private static void dumpSingleThread(Logger logger, Thread thread, StackTraceElement[] trace) 104 { 105 Map<CharSequence, Object> variables = new HashMap<>(); 106 variables.put("name", thread.getName()); 107 variables.put("isDaemon", thread.isDaemon() ? " daemon" : ""); 108 variables.put("priority", thread.getPriority()); 109 variables.put("threadIdDec", thread.getId()); 110 variables.put("state", thread.getState()); 111 112 ThreadDump throwable = new ThreadDump(); 113 throwable.setStackTrace(trace); 114 logger.warn(MapVariableInterpolator.interpolate(FORMAT, variables), throwable); 115 } 116 117 /** 118 * An exception used to hold the stacktrace of a thread. 119 */ 120 private static class ThreadDump extends RuntimeException 121 { 122 private static final long serialVersionUID = 1L; 123 124 /** 125 * @see java.lang.Throwable#fillInStackTrace() 126 */ 127 @Override 128 public synchronized Throwable fillInStackTrace() 129 { 130 // don't waste time to load the stack of the current thread 131 return null; 132 } 133 } 134}