1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.util;
20
21 import java.io.OutputStreamWriter;
22 import java.io.PrintStream;
23 import java.io.PrintWriter;
24 import java.lang.Thread.UncaughtExceptionHandler;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.nio.charset.StandardCharsets;
28 import java.util.Set;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.concurrent.ThreadFactory;
31 import java.util.concurrent.ThreadPoolExecutor;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicInteger;
34
35 import org.apache.hadoop.hbase.classification.InterfaceAudience;
36 import org.apache.hadoop.util.ReflectionUtils;
37 import org.apache.hadoop.util.StringUtils;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42
43
44 @InterfaceAudience.Private
45 public class Threads {
46 private static final Logger LOG = LoggerFactory.getLogger(Threads.class);
47 private static final AtomicInteger poolNumber = new AtomicInteger(1);
48
49 public static final UncaughtExceptionHandler LOGGING_EXCEPTION_HANDLER =
50 new UncaughtExceptionHandler() {
51 @Override
52 public void uncaughtException(Thread t, Throwable e) {
53 LOG.warn("Thread:" + t + " exited with Exception:"
54 + StringUtils.stringifyException(e));
55 }
56 };
57
58
59
60
61
62
63 public static Thread setDaemonThreadRunning(final Thread t) {
64 return setDaemonThreadRunning(t, t.getName());
65 }
66
67
68
69
70
71
72
73 public static Thread setDaemonThreadRunning(final Thread t,
74 final String name) {
75 return setDaemonThreadRunning(t, name, null);
76 }
77
78
79
80
81
82
83
84
85
86 public static Thread setDaemonThreadRunning(final Thread t,
87 final String name, final UncaughtExceptionHandler handler) {
88 t.setName(name);
89 if (handler != null) {
90 t.setUncaughtExceptionHandler(handler);
91 }
92 t.setDaemon(true);
93 t.start();
94 return t;
95 }
96
97
98
99
100
101 public static void shutdown(final Thread t) {
102 shutdown(t, 0);
103 }
104
105
106
107
108
109
110 public static void shutdown(final Thread t, final long joinwait) {
111 if (t == null) return;
112 while (t.isAlive()) {
113 try {
114 t.join(joinwait);
115 } catch (InterruptedException e) {
116 LOG.warn(t.getName() + "; joinwait=" + joinwait, e);
117 }
118 }
119 }
120
121
122
123
124
125
126
127 public static void threadDumpingIsAlive(final Thread t)
128 throws InterruptedException {
129 if (t == null) {
130 return;
131 }
132
133 while (t.isAlive()) {
134 t.join(60 * 1000);
135 if (t.isAlive()) {
136 printThreadInfo(System.out,
137 "Automatic Stack Trace every 60 seconds waiting on " +
138 t.getName());
139 }
140 }
141 }
142
143
144
145
146
147 public static void sleep(long millis) {
148 try {
149 Thread.sleep(millis);
150 } catch (InterruptedException e) {
151 e.printStackTrace();
152 Thread.currentThread().interrupt();
153 }
154 }
155
156
157
158
159
160
161 public static void sleepWithoutInterrupt(final long msToWait) {
162 long timeMillis = System.currentTimeMillis();
163 long endTime = timeMillis + msToWait;
164 boolean interrupted = false;
165 while (timeMillis < endTime) {
166 try {
167 Thread.sleep(endTime - timeMillis);
168 } catch (InterruptedException ex) {
169 interrupted = true;
170 }
171 timeMillis = System.currentTimeMillis();
172 }
173
174 if (interrupted) {
175 Thread.currentThread().interrupt();
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190 public static ThreadPoolExecutor getBoundedCachedThreadPool(
191 int maxCachedThread, long timeout, TimeUnit unit,
192 ThreadFactory threadFactory) {
193 ThreadPoolExecutor boundedCachedThreadPool =
194 new ThreadPoolExecutor(maxCachedThread, maxCachedThread, timeout,
195 unit, new LinkedBlockingQueue<Runnable>(), threadFactory);
196
197 boundedCachedThreadPool.allowCoreThreadTimeOut(true);
198 return boundedCachedThreadPool;
199 }
200
201
202
203
204
205
206
207
208 public static ThreadFactory getNamedThreadFactory(final String prefix) {
209 SecurityManager s = System.getSecurityManager();
210 final ThreadGroup threadGroup = (s != null) ? s.getThreadGroup() : Thread.currentThread()
211 .getThreadGroup();
212
213 return new ThreadFactory() {
214 final AtomicInteger threadNumber = new AtomicInteger(1);
215 private final int poolNumber = Threads.poolNumber.getAndIncrement();
216 final ThreadGroup group = threadGroup;
217
218 @Override
219 public Thread newThread(Runnable r) {
220 final String name = prefix + "-pool" + poolNumber + "-t" + threadNumber.getAndIncrement();
221 return new Thread(group, r, name);
222 }
223 };
224 }
225
226
227
228
229
230 public static ThreadFactory newDaemonThreadFactory(final String prefix) {
231 return newDaemonThreadFactory(prefix, null);
232 }
233
234
235
236
237
238
239
240
241 public static ThreadFactory newDaemonThreadFactory(final String prefix,
242 final UncaughtExceptionHandler handler) {
243 final ThreadFactory namedFactory = getNamedThreadFactory(prefix);
244 return new ThreadFactory() {
245 @Override
246 public Thread newThread(Runnable r) {
247 Thread t = namedFactory.newThread(r);
248 if (handler != null) {
249 t.setUncaughtExceptionHandler(handler);
250 } else {
251 t.setUncaughtExceptionHandler(LOGGING_EXCEPTION_HANDLER);
252 }
253 if (!t.isDaemon()) {
254 t.setDaemon(true);
255 }
256 if (t.getPriority() != Thread.NORM_PRIORITY) {
257 t.setPriority(Thread.NORM_PRIORITY);
258 }
259 return t;
260 }
261
262 };
263 }
264
265
266
267
268 public static void setLoggingUncaughtExceptionHandler(Thread t) {
269 t.setUncaughtExceptionHandler(LOGGING_EXCEPTION_HANDLER);
270 }
271
272 private static Method PRINT_THREAD_INFO_METHOD = null;
273 private static boolean PRINT_THREAD_INFO_METHOD_WITH_PRINTSTREAM = true;
274
275
276
277
278
279
280
281 public static synchronized void printThreadInfo(PrintStream stream, String title) {
282 if (PRINT_THREAD_INFO_METHOD == null) {
283 try {
284
285 PRINT_THREAD_INFO_METHOD = ReflectionUtils.class.getMethod("printThreadInfo",
286 PrintStream.class, String.class);
287 } catch (NoSuchMethodException e) {
288
289 PRINT_THREAD_INFO_METHOD_WITH_PRINTSTREAM = false;
290 try {
291 PRINT_THREAD_INFO_METHOD = ReflectionUtils.class.getMethod("printThreadInfo",
292 PrintWriter.class, String.class);
293 } catch (NoSuchMethodException e1) {
294 throw new RuntimeException("Cannot find method. Check hadoop jars linked", e1);
295 }
296 }
297 PRINT_THREAD_INFO_METHOD.setAccessible(true);
298 }
299
300 try {
301 if (PRINT_THREAD_INFO_METHOD_WITH_PRINTSTREAM) {
302 PRINT_THREAD_INFO_METHOD.invoke(null, stream, title);
303 } else {
304 PRINT_THREAD_INFO_METHOD.invoke(null,
305 new PrintWriter(new OutputStreamWriter(stream, StandardCharsets.UTF_8)), title);
306 }
307 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
308 throw new RuntimeException(e.getCause());
309 }
310 }
311
312
313
314
315
316 public static boolean isNonDaemonThreadRunning() {
317 AtomicInteger nonDaemonThreadCount = new AtomicInteger();
318 Set<Thread> threads = Thread.getAllStackTraces().keySet();
319 for (Thread t: threads) {
320
321 if (t.getId() != Thread.currentThread().getId() && !t.isDaemon()) {
322 nonDaemonThreadCount.getAndIncrement();
323 LOG.info("Non daemon thread {} is still alive", t.getName());
324 LOG.info(printStackTrace(t));
325 }
326 }
327 return nonDaemonThreadCount.get() > 0;
328 }
329
330
331
332
333 public static String printStackTrace(Thread t) {
334 StringBuilder sb = new StringBuilder();
335 for (StackTraceElement frame: t.getStackTrace()) {
336 sb.append("\n").append(" ").append(frame.toString());
337 }
338 return sb.toString();
339 }
340 }