1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3;
18
19 import java.time.Duration;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Objects;
23 import java.util.function.Function;
24 import java.util.function.Predicate;
25 import java.util.stream.Collectors;
26 import java.util.stream.Stream;
27
28 import org.apache.commons.lang3.function.Predicates;
29 import org.apache.commons.lang3.time.DurationUtils;
30
31 /**
32 * Helpers for {@link Thread} and {@link ThreadGroup}.
33 *
34 * <p>
35 * #ThreadSafe#
36 * </p>
37 *
38 * @see Thread
39 * @see ThreadGroup
40 * @since 3.5
41 */
42 public class ThreadUtils {
43
44 /**
45 * A predicate implementation which always returns true.
46 *
47 * @deprecated Use a {@link Predicate}.
48 */
49 @Deprecated
50 private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate {
51
52 private AlwaysTruePredicate() {
53 }
54
55 @Override
56 public boolean test(final Thread thread) {
57 return true;
58 }
59
60 @Override
61 public boolean test(final ThreadGroup threadGroup) {
62 return true;
63 }
64 }
65
66 /**
67 * Used internally, consider private.
68 * <p>
69 * A predicate implementation which matches a thread or thread group name.
70 * </p>
71 *
72 * @deprecated Use a {@link Predicate}.
73 */
74 @Deprecated
75 public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate {
76
77 private final String name;
78
79 /**
80 * Constructs an instance.
81 *
82 * @param name thread or thread group name.
83 * @throws NullPointerException if the name is {@code null}.
84 */
85 public NamePredicate(final String name) {
86 Objects.requireNonNull(name, "name");
87 this.name = name;
88 }
89
90 @Override
91 public boolean test(final Thread thread) {
92 return thread != null && thread.getName().equals(name);
93 }
94
95 @Override
96 public boolean test(final ThreadGroup threadGroup) {
97 return threadGroup != null && threadGroup.getName().equals(name);
98 }
99 }
100
101 /**
102 * A predicate for selecting thread groups.
103 *
104 * @deprecated Use a {@link Predicate}.
105 */
106 @Deprecated
107 // When breaking BC, replace this with Predicate<ThreadGroup>
108 @FunctionalInterface
109 public interface ThreadGroupPredicate {
110
111 /**
112 * Evaluates this predicate on the given thread group.
113 *
114 * @param threadGroup the thread group
115 * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false}
116 */
117 boolean test(ThreadGroup threadGroup);
118 }
119
120 /**
121 * A predicate implementation which matches a thread id.
122 *
123 * @deprecated Use a {@link Predicate}.
124 */
125 @Deprecated
126 public static class ThreadIdPredicate implements ThreadPredicate {
127
128 private final long threadId;
129
130 /**
131 * Predicate constructor
132 *
133 * @param threadId the threadId to match.
134 * @throws IllegalArgumentException if the threadId is zero or negative.
135 */
136 public ThreadIdPredicate(final long threadId) {
137 if (threadId <= 0) {
138 throw new IllegalArgumentException("The thread id must be greater than zero");
139 }
140 this.threadId = threadId;
141 }
142
143 @Override
144 public boolean test(final Thread thread) {
145 return thread != null && thread.getId() == threadId;
146 }
147 }
148
149 /**
150 * A predicate for selecting threads.
151 *
152 * @deprecated Use a {@link Predicate}.
153 */
154 @Deprecated
155 // When breaking BC, replace this with Predicate<Thread>
156 @FunctionalInterface
157 public interface ThreadPredicate {
158
159 /**
160 * Evaluates this predicate on the given thread.
161 *
162 * @param thread the thread
163 * @return {@code true} if the thread matches the predicate, otherwise {@code false}
164 */
165 boolean test(Thread thread);
166 }
167
168 /**
169 * Predicate which always returns true.
170 *
171 * @deprecated Use a {@link Predicate}.
172 */
173 @Deprecated
174 public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate();
175
176 /**
177 * Finds the active thread with the specified id.
178 *
179 * @param threadId The thread id.
180 * @return The thread with the specified id or {@code null} if no such thread exists.
181 * @throws IllegalArgumentException if the specified id is zero or negative.
182 * @throws SecurityException if the current thread cannot access the system thread group.
183 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
184 */
185 public static Thread findThreadById(final long threadId) {
186 if (threadId <= 0) {
187 throw new IllegalArgumentException("The thread id must be greater than zero");
188 }
189 final Collection<Thread> result = findThreads((Predicate<Thread>) t -> t != null && t.getId() == threadId);
190 return result.isEmpty() ? null : result.iterator().next();
191 }
192
193 /**
194 * Finds the active thread with the specified id if it belongs to a thread group with the specified group name.
195 *
196 * @param threadId The thread id.
197 * @param threadGroupName The thread group name.
198 * @return The threads which belongs to a thread group with the specified group name and the thread's id match the specified id. {@code null} is returned if
199 * no such thread exists.
200 * @throws NullPointerException if the group name is null.
201 * @throws IllegalArgumentException if the specified id is zero or negative.
202 * @throws SecurityException if the current thread cannot access the system thread group.
203 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
204 */
205 public static Thread findThreadById(final long threadId, final String threadGroupName) {
206 Objects.requireNonNull(threadGroupName, "threadGroupName");
207 final Thread thread = findThreadById(threadId);
208 if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) {
209 return thread;
210 }
211 return null;
212 }
213
214 /**
215 * Finds the active thread with the specified id if it belongs to the specified thread group.
216 *
217 * @param threadId The thread id.
218 * @param threadGroup The thread group.
219 * @return The thread which belongs to a specified thread group and the thread's id match the specified id. {@code null} is returned if no such thread
220 * exists.
221 * @throws NullPointerException if {@code threadGroup == null}.
222 * @throws IllegalArgumentException if the specified id is zero or negative.
223 * @throws SecurityException if the current thread cannot access the system thread group.
224 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
225 */
226 public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) {
227 Objects.requireNonNull(threadGroup, "threadGroup");
228 final Thread thread = findThreadById(threadId);
229 if (thread != null && threadGroup.equals(thread.getThreadGroup())) {
230 return thread;
231 }
232 return null;
233 }
234
235 /**
236 * Finds all active thread groups which match the given predicate.
237 *
238 * @param predicate the predicate.
239 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate.
240 * @throws NullPointerException if the predicate is null.
241 * @throws SecurityException if the current thread cannot access the system thread group.
242 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
243 * @since 3.13.0
244 */
245 public static Collection<ThreadGroup> findThreadGroups(final Predicate<ThreadGroup> predicate) {
246 return findThreadGroups(getSystemThreadGroup(), true, predicate);
247 }
248
249 /**
250 * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups).
251 *
252 * @param threadGroup the thread group.
253 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group.
254 * @param predicate the predicate.
255 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group.
256 * @throws NullPointerException if the given group or predicate is null.
257 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
258 * @since 3.13.0
259 */
260 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate<ThreadGroup> predicate) {
261 Objects.requireNonNull(threadGroup, "threadGroup");
262 Objects.requireNonNull(predicate, "predicate");
263 int count = threadGroup.activeGroupCount();
264 ThreadGroup[] threadGroups;
265 do {
266 threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size
267 count = threadGroup.enumerate(threadGroups, recurse);
268 //return value of enumerate() must be strictly less than the array size according to Javadoc
269 } while (count >= threadGroups.length);
270 return Collections.unmodifiableCollection(Stream.of(threadGroups).limit(count).filter(predicate).collect(Collectors.toList()));
271 }
272
273 /**
274 * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups).
275 *
276 * @param threadGroup the thread group.
277 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group.
278 * @param predicate the predicate.
279 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group.
280 * @throws NullPointerException if the given group or predicate is null.
281 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
282 * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}.
283 */
284 @Deprecated
285 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) {
286 return findThreadGroups(threadGroup, recurse, (Predicate<ThreadGroup>) predicate::test);
287 }
288
289 /**
290 * Finds all active thread groups which match the given predicate.
291 *
292 * @param predicate the predicate.
293 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate.
294 * @throws NullPointerException if the predicate is null.
295 * @throws SecurityException if the current thread cannot access the system thread group.
296 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
297 * @deprecated Use {@link #findThreadGroups(Predicate)}.
298 */
299 @Deprecated
300 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroupPredicate predicate) {
301 return findThreadGroups(getSystemThreadGroup(), true, predicate);
302 }
303
304 /**
305 * Finds active thread groups with the specified group name.
306 *
307 * @param threadGroupName The thread group name.
308 * @return the thread groups with the specified group name or an empty collection if no such thread group exists. The collection returned is always
309 * unmodifiable.
310 * @throws NullPointerException if group name is null.
311 * @throws SecurityException if the current thread cannot access the system thread group.
312 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
313 */
314 public static Collection<ThreadGroup> findThreadGroupsByName(final String threadGroupName) {
315 return findThreadGroups(predicateThreadGroup(threadGroupName));
316 }
317
318 /**
319 * Finds all active threads which match the given predicate.
320 *
321 * @param predicate the predicate.
322 * @return An unmodifiable {@link Collection} of active threads matching the given predicate.
323 * @throws NullPointerException if the predicate is null.
324 * @throws SecurityException if the current thread cannot access the system thread group.
325 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
326 * @since 3.13.0
327 */
328 public static Collection<Thread> findThreads(final Predicate<Thread> predicate) {
329 return findThreads(getSystemThreadGroup(), true, predicate);
330 }
331
332 /**
333 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
334 *
335 * @param threadGroup the thread group.
336 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group.
337 * @param predicate the predicate.
338 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group.
339 * @throws NullPointerException if the given group or predicate is null.
340 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
341 * @since 3.13.0
342 */
343 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate<Thread> predicate) {
344 Objects.requireNonNull(threadGroup, "The group must not be null");
345 Objects.requireNonNull(predicate, "The predicate must not be null");
346 int count = threadGroup.activeCount();
347 Thread[] threads;
348 do {
349 threads = new Thread[count + count / 2 + 1]; //slightly grow the array size
350 count = threadGroup.enumerate(threads, recurse);
351 //return value of enumerate() must be strictly less than the array size according to javadoc
352 } while (count >= threads.length);
353 return Collections.unmodifiableCollection(Stream.of(threads).limit(count).filter(predicate).collect(Collectors.toList()));
354 }
355
356 /**
357 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
358 *
359 * @param threadGroup the thread group.
360 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group.
361 * @param predicate the predicate.
362 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group.
363 * @throws NullPointerException if the given group or predicate is null.
364 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
365 * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}.
366 */
367 @Deprecated
368 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) {
369 return findThreads(threadGroup, recurse, (Predicate<Thread>) predicate::test);
370 }
371
372 /**
373 * Finds all active threads which match the given predicate.
374 *
375 * @param predicate the predicate.
376 * @return An unmodifiable {@link Collection} of active threads matching the given predicate.
377 * @throws NullPointerException if the predicate is null.
378 * @throws SecurityException if the current thread cannot access the system thread group.
379 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
380 * @deprecated Use {@link #findThreads(Predicate)}.
381 */
382 @Deprecated
383 public static Collection<Thread> findThreads(final ThreadPredicate predicate) {
384 return findThreads(getSystemThreadGroup(), true, predicate);
385 }
386
387 /**
388 * Finds active threads with the specified name.
389 *
390 * @param threadName The thread name.
391 * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable.
392 * @throws NullPointerException if the specified name is null.
393 * @throws SecurityException if the current thread cannot access the system thread group.
394 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
395 */
396 public static Collection<Thread> findThreadsByName(final String threadName) {
397 return findThreads(predicateThread(threadName));
398 }
399
400 /**
401 * Finds active threads with the specified name if they belong to a thread group with the specified group name.
402 *
403 * @param threadName The thread name.
404 * @param threadGroupName The thread group name.
405 * @return The threads which belongs to a thread group with the specified group name and the thread's name match the specified name, An empty collection is
406 * returned if no such thread exists. The collection returned is always unmodifiable.
407 * @throws NullPointerException if the specified thread name or group name is null.
408 * @throws SecurityException if the current thread cannot access the system thread group.
409 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
410 */
411 public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) {
412 Objects.requireNonNull(threadName, "threadName");
413 Objects.requireNonNull(threadGroupName, "threadGroupName");
414 return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream()
415 .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList()));
416 }
417
418 /**
419 * Finds active threads with the specified name if they belong to a specified thread group.
420 *
421 * @param threadName The thread name.
422 * @param threadGroup The thread group.
423 * @return The threads which belongs to a thread group and the thread's name match the specified name, An empty collection is returned if no such thread
424 * exists. The collection returned is always unmodifiable.
425 * @throws NullPointerException if the specified thread name or group is null.
426 * @throws SecurityException if the current thread cannot access the system thread group.
427 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
428 */
429 public static Collection<Thread> findThreadsByName(final String threadName, final ThreadGroup threadGroup) {
430 return findThreads(threadGroup, false, predicateThread(threadName));
431 }
432
433 /**
434 * Gets all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed).
435 *
436 * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable.
437 * @throws SecurityException if the current thread cannot access the system thread group.
438 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
439 */
440 public static Collection<ThreadGroup> getAllThreadGroups() {
441 return findThreadGroups(Predicates.truePredicate());
442 }
443
444 /**
445 * Gets all active threads (A thread is active if it has been started and has not yet died).
446 *
447 * @return all active threads. The collection returned is always unmodifiable.
448 * @throws SecurityException if the current thread cannot access the system thread group.
449 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
450 */
451 public static Collection<Thread> getAllThreads() {
452 return findThreads(Predicates.truePredicate());
453 }
454
455 /**
456 * Gets the system thread group (sometimes also referred as "root thread group").
457 * <p>
458 * This method returns null if this thread has died (been stopped).
459 * </p>
460 *
461 * @return the system thread group.
462 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
463 */
464 public static ThreadGroup getSystemThreadGroup() {
465 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
466 while (threadGroup != null && threadGroup.getParent() != null) {
467 threadGroup = threadGroup.getParent();
468 }
469 return threadGroup;
470 }
471
472 /**
473 * Waits for the given thread to die for the given duration. Implemented using {@link Thread#join(long, int)}.
474 *
475 * @param thread The thread to join.
476 * @param duration How long to wait.
477 * @throws InterruptedException if any thread has interrupted the current thread.
478 * @see Thread#join(long, int)
479 * @since 3.12.0
480 */
481 public static void join(final Thread thread, final Duration duration) throws InterruptedException {
482 DurationUtils.accept(thread::join, duration);
483 }
484
485 private static <T> Predicate<T> namePredicate(final String name, final Function<T, String> nameGetter) {
486 return (Predicate<T>) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name));
487 }
488
489 private static Predicate<Thread> predicateThread(final String threadName) {
490 return namePredicate(threadName, Thread::getName);
491 }
492
493 private static Predicate<ThreadGroup> predicateThreadGroup(final String threadGroupName) {
494 return namePredicate(threadGroupName, ThreadGroup::getName);
495 }
496
497 /**
498 * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}.
499 *
500 * @param duration How long to sleep.
501 * @throws InterruptedException if any thread has interrupted the current thread.
502 * @see Thread#sleep(long, int)
503 * @since 3.12.0
504 */
505 public static void sleep(final Duration duration) throws InterruptedException {
506 DurationUtils.accept(Thread::sleep, duration);
507 }
508
509 /**
510 * Sleeps for the given duration without throwing {@link InterruptedException}.
511 * <p>
512 * The sleep duration may be shorter than the given duration if we catch a {@link InterruptedException}.
513 * </p>
514 *
515 * @param duration the length of time to sleep.
516 * @see #sleep(Duration)
517 * @see Thread#interrupted()
518 * @since 3.13.0
519 */
520 public static void sleepQuietly(final Duration duration) {
521 try {
522 sleep(duration);
523 } catch (final InterruptedException ignore) {
524 Thread.currentThread().interrupt();
525 }
526 }
527
528 /**
529 * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ThreadUtils.getAllThreads()}
530 * <p>
531 * This constructor is public to permit tools that require a JavaBean instance to operate.
532 * </p>
533 *
534 * @deprecated TODO Make private in 4.0.
535 */
536 @Deprecated
537 public ThreadUtils() {
538 // empty
539 }
540 }