1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.monitor.integration;
20
21 import java.lang.management.ManagementFactory;
22 import java.lang.management.ThreadInfo;
23 import java.lang.management.ThreadMXBean;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.security.Security;
27 import java.util.HashMap;
28 import java.util.Map;
29
30
31
32
33
34
35
36
37 public class JavaMonitorTools
38 {
39 private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
40
41 private static Method findDeadlockMethod = null;
42
43 static
44 {
45 try
46 {
47 findDeadlockMethod = ThreadMXBean.class.getMethod("findDeadlockedThreads");
48 }
49 catch (Exception ignored)
50 {
51
52 try
53 {
54 findDeadlockMethod = ThreadMXBean.class.getMethod("findMonitorDeadlockedThreads");
55 }
56 catch (SecurityException e)
57 {
58 e.printStackTrace();
59 }
60 catch (NoSuchMethodException e)
61 {
62 e.printStackTrace();
63 }
64 }
65 }
66
67 private ThreadInfo[] findDeadlock()
68 throws IllegalAccessException, InvocationTargetException
69 {
70 final long[] threadIds = (long[])findDeadlockMethod.invoke(threadMXBean,(Object[])null);
71
72 if (threadIds == null || threadIds.length < 1)
73 {
74
75 return null;
76 }
77
78 final ThreadInfo[] threads = threadMXBean.getThreadInfo(threadIds,Integer.MAX_VALUE);
79 return threads;
80 }
81
82 public String getDeadlockStacktraces()
83 {
84 try
85 {
86 final ThreadInfo[] threads = findDeadlock();
87 if (threads == null)
88 {
89
90 return null;
91 }
92
93 return stacktraces(threads,0);
94 }
95 catch (Exception e)
96 {
97 return e.getMessage();
98 }
99 }
100
101 private static final int MAX_STACK = 10;
102
103 private String stacktraces(final ThreadInfo[] threads, final int i)
104 {
105 if (i >= threads.length)
106 {
107 return "";
108 }
109 final ThreadInfo thread = threads[i];
110
111 final StringBuilder trace = new StringBuilder();
112 for (int stack_i = 0; stack_i < Math.min(thread.getStackTrace().length,MAX_STACK); stack_i++)
113 {
114 if (stack_i == (MAX_STACK - 1))
115 {
116 trace.append(" ...");
117 }
118 else
119 {
120 trace.append(" at ").append(thread.getStackTrace()[stack_i]).append("\n");
121 }
122 }
123
124 return "\"" + thread.getThreadName() + "\", id " + thread.getThreadId() + " is " + thread.getThreadState() + " on " + thread.getLockName()
125 + ", owned by " + thread.getLockOwnerName() + ", id " + thread.getLockOwnerId() + "\n" + trace + "\n\n" + stacktraces(threads,i + 1);
126 }
127
128
129
130
131
132
133 private long lastSampled = 0L;
134
135 private final Map<Thread.State, Integer> states = new HashMap<Thread.State, Integer>();
136
137 public int getThreadsBlocked()
138 {
139 sampleThreads();
140
141 return states.get(Thread.State.BLOCKED);
142 }
143
144 public int getThreadsNew()
145 {
146 sampleThreads();
147
148 return states.get(Thread.State.NEW);
149 }
150
151 public int getThreadsTerminated()
152 {
153 sampleThreads();
154
155 return states.get(Thread.State.TERMINATED);
156 }
157
158 public int getThreadsTimedWaiting()
159 {
160 sampleThreads();
161
162 return states.get(Thread.State.TIMED_WAITING);
163 }
164
165 public int getThreadsWaiting()
166 {
167 sampleThreads();
168
169 return states.get(Thread.State.WAITING);
170 }
171
172 public int getThreadsRunnable()
173 {
174 sampleThreads();
175
176 return states.get(Thread.State.RUNNABLE);
177 }
178
179 private synchronized void sampleThreads()
180 {
181 if ((lastSampled + 50L) < System.currentTimeMillis())
182 {
183 lastSampled = System.currentTimeMillis();
184 for (final Thread.State state : Thread.State.values())
185 {
186 states.put(state,0);
187 }
188
189 for (final ThreadInfo thread : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds()))
190 {
191 if (thread != null)
192 {
193 final Thread.State state = thread.getThreadState();
194 states.put(state,states.get(state) + 1);
195 }
196 else
197 {
198 states.put(Thread.State.TERMINATED,states.get(Thread.State.TERMINATED) + 1);
199 }
200 }
201 }
202 }
203
204 private static final String POLICY = "sun.net.InetAddressCachePolicy";
205
206 public int getCacheSeconds() throws ClassNotFoundException,
207 IllegalAccessException, InvocationTargetException,
208 NoSuchMethodException {
209 final Class policy = Class.forName(POLICY);
210 final Object returnValue = policy.getMethod("get", (Class[]) null)
211 .invoke(null, (Object[]) null);
212 Integer seconds = (Integer) returnValue;
213
214 return seconds.intValue();
215 }
216
217 public int getCacheNegativeSeconds() throws ClassNotFoundException,
218 IllegalAccessException, InvocationTargetException,
219 NoSuchMethodException {
220 final Class policy = Class.forName(POLICY);
221 final Object returnValue = policy.getMethod("getNegative",
222 (Class[]) null).invoke(null, (Object[]) null);
223 Integer seconds = (Integer) returnValue;
224
225 return seconds.intValue();
226 }
227
228 private static final String DEFAULT = "default";
229
230 private static final String SECURITY = "security";
231
232 private static final String SYSTEM = "system";
233
234 private static final String BOTH = "both";
235
236 private static final String SECURITY_TTL = "networkaddress.cache.ttl";
237
238 private static final String SYSTEM_TTL = "sun.net.inetaddr.ttl";
239
240 private static final String SECURITY_NEGATIVE_TTL = "networkaddress.cache.negative.ttl";
241
242 private static final String SYSTEM_NEGATIVE_TTL = "sun.net.inetaddr.negative.ttl";
243
244 public String getCacheTweakedFrom() {
245 if (Security.getProperty(SECURITY_TTL) != null) {
246 if (System.getProperty(SYSTEM_TTL) != null) {
247 return BOTH;
248 }
249
250 return SECURITY;
251 }
252
253 if (System.getProperty(SYSTEM_TTL) != null) {
254 return SYSTEM;
255 }
256
257 return DEFAULT;
258 }
259
260 public String getCacheNegativeTweakedFrom() {
261 if (Security.getProperty(SECURITY_NEGATIVE_TTL) != null) {
262 if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
263 return BOTH;
264 }
265
266 return SECURITY;
267 }
268
269 if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
270 return SYSTEM;
271 }
272
273 return DEFAULT;
274 }
275 }