2828import java .lang .management .ManagementFactory ;
2929import java .lang .management .ThreadInfo ;
3030import java .lang .management .ThreadMXBean ;
31+ import java .lang .management .MonitorInfo ;
32+ import java .lang .management .LockInfo ;
3133import java .util .concurrent .ScheduledThreadPoolExecutor ;
3234import java .util .concurrent .TimeUnit ;
3335
3436public class ThreadDump extends AbstractLifecycleListener {
3537
36- private Logger log = LoggerFactory .getLogger (ThreadDump .class );
38+ private static final Logger log = LoggerFactory .getLogger (ThreadDump .class );
39+
40+ private static final int MAX_FRAMES = 40 ;
3741
3842 @ Nullable
3943 private ScheduledThreadPoolExecutor executor ;
@@ -66,7 +70,7 @@ public void run() {
6670 ThreadMXBean threadMXBean = ManagementFactory .getThreadMXBean ();
6771 StringBuilder sb = new StringBuilder ();
6872 for (ThreadInfo threadInfo : threadMXBean .dumpAllThreads (true , true )) {
69- sb .append (threadInfo .toString ());
73+ sb .append (ThreadDump .toString (threadInfo ));
7074 }
7175
7276 log .debug ("thread dump: \n \n {}" , sb );
@@ -82,4 +86,83 @@ public void stop() throws Exception {
8286 }
8387 ExecutorUtils .shutdownAndWaitTermination (executor );
8488 }
89+
90+ /**
91+ * Copy of {@link ThreadInfo#toString()} with a higher frame size as default implementation.
92+ *
93+ * @param threadInfo thread info
94+ * @return thread info as string
95+ */
96+ private static String toString (ThreadInfo threadInfo ) {
97+ StringBuilder sb = new StringBuilder ("\" " + threadInfo .getThreadName () + "\" " +
98+ // note: daemon and priority now available < java9
99+ " Id=" + threadInfo .getThreadId () + " " +
100+ threadInfo .getThreadState ());
101+ if (threadInfo .getLockName () != null ) {
102+ sb .append (" on " + threadInfo .getLockName ());
103+ }
104+ if (threadInfo .getLockOwnerName () != null ) {
105+ sb .append (" owned by \" " + threadInfo .getLockOwnerName () +
106+ "\" Id=" + threadInfo .getLockOwnerId ());
107+ }
108+ if (threadInfo .isSuspended ()) {
109+ sb .append (" (suspended)" );
110+ }
111+ if (threadInfo .isInNative ()) {
112+ sb .append (" (in native)" );
113+ }
114+ sb .append ('\n' );
115+
116+ StackTraceElement [] stackTrace = threadInfo .getStackTrace ();
117+ int i = 0 ;
118+ for (; i < stackTrace .length && i < MAX_FRAMES ; i ++) {
119+ StackTraceElement ste = stackTrace [i ];
120+ sb .append ("\t at " + ste .toString ());
121+ sb .append ('\n' );
122+ if (i == 0 && threadInfo .getLockInfo () != null ) {
123+ Thread .State ts = threadInfo .getThreadState ();
124+ switch (ts ) {
125+ case BLOCKED :
126+ sb .append ("\t - blocked on " + threadInfo .getLockInfo ());
127+ sb .append ('\n' );
128+ break ;
129+ case WAITING :
130+ sb .append ("\t - waiting on " + threadInfo .getLockInfo ());
131+ sb .append ('\n' );
132+ break ;
133+ case TIMED_WAITING :
134+ sb .append ("\t - waiting on " + threadInfo .getLockInfo ());
135+ sb .append ('\n' );
136+ break ;
137+ default :
138+ }
139+ }
140+
141+ for (MonitorInfo mi : threadInfo .getLockedMonitors ()) {
142+ if (mi .getLockedStackDepth () == i ) {
143+ sb .append ("\t - locked " + mi );
144+ sb .append ('\n' );
145+ }
146+ }
147+ }
148+ if (i < stackTrace .length ) {
149+ sb .append ("\t ..." );
150+ sb .append ('\n' );
151+ }
152+
153+ LockInfo [] locks = threadInfo .getLockedSynchronizers ();
154+ if (locks .length > 0 ) {
155+ sb .append ("\n \t Number of locked synchronizers = " + locks .length );
156+ sb .append ('\n' );
157+ for (LockInfo li : locks ) {
158+ sb .append ("\t - " + li );
159+ sb .append ('\n' );
160+ }
161+ }
162+ sb .append ('\n' );
163+ return sb .toString ();
164+
165+ }
166+
167+
85168}
0 commit comments