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 * @param threadGroup the thread group
114 * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false}
115 */
116 boolean test(ThreadGroup threadGroup);
117 }
118
119 /**
120 * A predicate implementation which matches a thread id.
121 *
122 * @deprecated Use a {@link Predicate}.
123 */
124 @Deprecated
125 public static class ThreadIdPredicate implements ThreadPredicate {
126
127 private final long threadId;
128
129 /**
130 * Predicate constructor
131 *
132 * @param threadId the threadId to match.
133 * @throws IllegalArgumentException if the threadId is zero or negative.
134 */
135 public ThreadIdPredicate(final long threadId) {
136 if (threadId <= 0) {
137 throw new IllegalArgumentException("The thread id must be greater than zero");
138 }
139 this.threadId = threadId;
140 }
141
142 @Override
143 public boolean test(final Thread thread) {
144 return thread != null && thread.getId() == threadId;
145 }
146 }
147
148 /**
149 * A predicate for selecting threads.
150 *
151 * @deprecated Use a {@link Predicate}.
152 */
153 @Deprecated
154 // When breaking BC, replace this with Predicate<Thread>
155 @FunctionalInterface
156 public interface ThreadPredicate {
157
158 /**
159 * Evaluates this predicate on the given thread.
160 * @param thread the thread
161 * @return {@code true} if the thread matches the predicate, otherwise {@code false}
162 */
163 boolean test(Thread thread);
164 }
165
166 /**
167 * Predicate which always returns true.
168 *
169 * @deprecated Use a {@link Predicate}.
170 */
171 @Deprecated
172 public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate();
173
174 /**
175 * Finds the active thread with the specified id.
176 *
177 * @param threadId The thread id.
178 * @return The thread with the specified id or {@code null} if no such thread exists.
179 * @throws IllegalArgumentException if the specified id is zero or negative.
180 * @throws SecurityException if the current thread cannot access the system thread group.
181 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
182 */
183 public static Thread findThreadById(final long threadId) {
184 if (threadId <= 0) {
185 throw new IllegalArgumentException("The thread id must be greater than zero");
186 }
187 final Collection<Thread> result = findThreads((Predicate<Thread>) t -> t != null && t.getId() == threadId);
188 return result.isEmpty() ? null : result.iterator().next();
189 }
190
191 /**
192 * Finds the active thread with the specified id if it belongs to a thread group with the specified group name.
193 *
194 * @param threadId The thread id.
195 * @param threadGroupName The thread group name.
196 * @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
197 * no such thread exists.
198 * @throws NullPointerException if the group name is null.
199 * @throws IllegalArgumentException if the specified id is zero or negative.
200 * @throws SecurityException if the current thread cannot access the system thread group.
201 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
202 */
203 public static Thread findThreadById(final long threadId, final String threadGroupName) {
204 Objects.requireNonNull(threadGroupName, "threadGroupName");
205 final Thread thread = findThreadById(threadId);
206 if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) {
207 return thread;
208 }
209 return null;
210 }
211
212 /**
213 * Finds the active thread with the specified id if it belongs to the specified thread group.
214 *
215 * @param threadId The thread id.
216 * @param threadGroup The thread group.
217 * @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
218 * exists.
219 * @throws NullPointerException if {@code threadGroup == null}.
220 * @throws IllegalArgumentException if the specified id is zero or negative.
221 * @throws SecurityException if the current thread cannot access the system thread group.
222 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
223 */
224 public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) {
225 Objects.requireNonNull(threadGroup, "threadGroup");
226 final Thread thread = findThreadById(threadId);
227 if (thread != null && threadGroup.equals(thread.getThreadGroup())) {
228 return thread;
229 }
230 return null;
231 }
232
233 /**
234 * Finds all active thread groups which match the given predicate.
235 *
236 * @param predicate the predicate.
237 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate.
238 * @throws NullPointerException if the predicate is null.
239 * @throws SecurityException if the current thread cannot access the system thread group.
240 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
241 * @since 3.13.0
242 */
243 public static Collection<ThreadGroup> findThreadGroups(final Predicate<ThreadGroup> predicate) {
244 return findThreadGroups(getSystemThreadGroup(), true, predicate);
245 }
246
247 /**
248 * 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).
249 *
250 * @param threadGroup the thread group.
251 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group.
252 * @param predicate the predicate.
253 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group.
254 * @throws NullPointerException if the given group or predicate is null.
255 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
256 * @since 3.13.0
257 */
258 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate<ThreadGroup> predicate) {
259 Objects.requireNonNull(threadGroup, "threadGroup");
260 Objects.requireNonNull(predicate, "predicate");
261 int count = threadGroup.activeGroupCount();
262 ThreadGroup[] threadGroups;
263 do {
264 threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size
265 count = threadGroup.enumerate(threadGroups, recurse);
266 //return value of enumerate() must be strictly less than the array size according to Javadoc
267 } while (count >= threadGroups.length);
268 return Collections.unmodifiableCollection(Stream.of(threadGroups).limit(count).filter(predicate).collect(Collectors.toList()));
269 }
270
271 /**
272 * 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).
273 *
274 * @param threadGroup the thread group.
275 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group.
276 * @param predicate the predicate.
277 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group.
278 * @throws NullPointerException if the given group or predicate is null.
279 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
280 * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}.
281 */
282 @Deprecated
283 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) {
284 return findThreadGroups(threadGroup, recurse, (Predicate<ThreadGroup>) predicate::test);
285 }
286
287 /**
288 * Finds all active thread groups which match the given predicate.
289 *
290 * @param predicate the predicate.
291 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate.
292 * @throws NullPointerException if the predicate is null.
293 * @throws SecurityException if the current thread cannot access the system thread group.
294 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
295 * @deprecated Use {@link #findThreadGroups(Predicate)}.
296 */
297 @Deprecated
298 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroupPredicate predicate) {
299 return findThreadGroups(getSystemThreadGroup(), true, predicate);
300 }
301
302 /**
303 * Finds active thread groups with the specified group name.
304 *
305 * @param threadGroupName The thread group name.
306 * @return the thread groups with the specified group name or an empty collection if no such thread group exists. The collection returned is always
307 * unmodifiable.
308 * @throws NullPointerException if group name is null.
309 * @throws SecurityException if the current thread cannot access the system thread group.
310 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
311 */
312 public static Collection<ThreadGroup> findThreadGroupsByName(final String threadGroupName) {
313 return findThreadGroups(predicateThreadGroup(threadGroupName));
314 }
315
316 /**
317 * Finds all active threads which match the given predicate.
318 *
319 * @param predicate the predicate.
320 * @return An unmodifiable {@link Collection} of active threads matching the given predicate.
321 * @throws NullPointerException if the predicate is null.
322 * @throws SecurityException if the current thread cannot access the system thread group.
323 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
324 * @since 3.13.0
325 */
326 public static Collection<Thread> findThreads(final Predicate<Thread> predicate) {
327 return findThreads(getSystemThreadGroup(), true, predicate);
328 }
329
330 /**
331 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
332 *
333 * @param threadGroup the thread group.
334 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group.
335 * @param predicate the predicate.
336 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group.
337 * @throws NullPointerException if the given group or predicate is null.
338 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
339 * @since 3.13.0
340 */
341 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate<Thread> predicate) {
342 Objects.requireNonNull(threadGroup, "The group must not be null");
343 Objects.requireNonNull(predicate, "The predicate must not be null");
344 int count = threadGroup.activeCount();
345 Thread[] threads;
346 do {
347 threads = new Thread[count + count / 2 + 1]; //slightly grow the array size
348 count = threadGroup.enumerate(threads, recurse);
349 //return value of enumerate() must be strictly less than the array size according to javadoc
350 } while (count >= threads.length);
351 return Collections.unmodifiableCollection(Stream.of(threads).limit(count).filter(predicate).collect(Collectors.toList()));
352 }
353
354 /**
355 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
356 *
357 * @param threadGroup the thread group.
358 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group.
359 * @param predicate the predicate.
360 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group.
361 * @throws NullPointerException if the given group or predicate is null.
362 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
363 * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}.
364 */
365 @Deprecated
366 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) {
367 return findThreads(threadGroup, recurse, (Predicate<Thread>) predicate::test);
368 }
369
370 /**
371 * Finds all active threads which match the given predicate.
372 *
373 * @param predicate the predicate.
374 * @return An unmodifiable {@link Collection} of active threads matching the given predicate.
375 * @throws NullPointerException if the predicate is null.
376 * @throws SecurityException if the current thread cannot access the system thread group.
377 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
378 * @deprecated Use {@link #findThreads(Predicate)}.
379 */
380 @Deprecated
381 public static Collection<Thread> findThreads(final ThreadPredicate predicate) {
382 return findThreads(getSystemThreadGroup(), true, predicate);
383 }
384
385 /**
386 * Finds active threads with the specified name.
387 *
388 * @param threadName The thread name.
389 * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable.
390 * @throws NullPointerException if the specified name is null.
391 * @throws SecurityException if the current thread cannot access the system thread group.
392 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
393 */
394 public static Collection<Thread> findThreadsByName(final String threadName) {
395 return findThreads(predicateThread(threadName));
396 }
397
398 /**
399 * Finds active threads with the specified name if they belong to a thread group with the specified group name.
400 *
401 * @param threadName The thread name.
402 * @param threadGroupName The thread group name.
403 * @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
404 * returned if no such thread exists. The collection returned is always unmodifiable.
405 * @throws NullPointerException if the specified thread name or group name is null.
406 * @throws SecurityException if the current thread cannot access the system thread group.
407 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
408 */
409 public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) {
410 Objects.requireNonNull(threadName, "threadName");
411 Objects.requireNonNull(threadGroupName, "threadGroupName");
412 return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream()
413 .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList()));
414 }
415
416 /**
417 * Finds active threads with the specified name if they belong to a specified thread group.
418 *
419 * @param threadName The thread name.
420 * @param threadGroup The thread group.
421 * @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
422 * exists. The collection returned is always unmodifiable.
423 * @throws NullPointerException if the specified thread name or group is null.
424 * @throws SecurityException if the current thread cannot access the system thread group.
425 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
426 */
427 public static Collection<Thread> findThreadsByName(final String threadName, final ThreadGroup threadGroup) {
428 return findThreads(threadGroup, false, predicateThread(threadName));
429 }
430
431 /**
432 * Gets all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed).
433 *
434 * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable.
435 * @throws SecurityException if the current thread cannot access the system thread group.
436 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
437 */
438 public static Collection<ThreadGroup> getAllThreadGroups() {
439 return findThreadGroups(Predicates.truePredicate());
440 }
441
442 /**
443 * Gets all active threads (A thread is active if it has been started and has not yet died).
444 *
445 * @return all active threads. The collection returned is always unmodifiable.
446 * @throws SecurityException if the current thread cannot access the system thread group.
447 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
448 */
449 public static Collection<Thread> getAllThreads() {
450 return findThreads(Predicates.truePredicate());
451 }
452
453 /**
454 * Gets the system thread group (sometimes also referred as "root thread group").
455 * <p>
456 * This method returns null if this thread has died (been stopped).
457 * </p>
458 *
459 * @return the system thread group.
460 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group.
461 */
462 public static ThreadGroup getSystemThreadGroup() {
463 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
464 while (threadGroup != null && threadGroup.getParent() != null) {
465 threadGroup = threadGroup.getParent();
466 }
467 return threadGroup;
468 }
469
470 /**
471 * Waits for the given thread to die for the given duration. Implemented using {@link Thread#join(long, int)}.
472 *
473 * @param thread The thread to join.
474 * @param duration How long to wait.
475 * @throws InterruptedException if any thread has interrupted the current thread.
476 * @see Thread#join(long, int)
477 * @since 3.12.0
478 */
479 public static void join(final Thread thread, final Duration duration) throws InterruptedException {
480 DurationUtils.accept(thread::join, duration);
481 }
482
483 private static <T> Predicate<T> namePredicate(final String name, final Function<T, String> nameGetter) {
484 return (Predicate<T>) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name));
485 }
486
487 private static Predicate<Thread> predicateThread(final String threadName) {
488 return namePredicate(threadName, Thread::getName);
489 }
490
491 private static Predicate<ThreadGroup> predicateThreadGroup(final String threadGroupName) {
492 return namePredicate(threadGroupName, ThreadGroup::getName);
493 }
494
495 /**
496 * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}.
497 *
498 * @param duration How long to sleep.
499 * @throws InterruptedException if any thread has interrupted the current thread.
500 * @see Thread#sleep(long, int)
501 * @since 3.12.0
502 */
503 public static void sleep(final Duration duration) throws InterruptedException {
504 DurationUtils.accept(Thread::sleep, duration);
505 }
506
507 /**
508 * Sleeps for the given duration while ignoring {@link InterruptedException}.
509 * <p>
510 * The sleep duration may be shorter than duration if we catch a {@link InterruptedException}.
511 * </p>
512 *
513 * @param duration the length of time to sleep.
514 * @since 3.13.0
515 */
516 public static void sleepQuietly(final Duration duration) {
517 try {
518 sleep(duration);
519 } catch (final InterruptedException ignore) {
520 // Ignore & be quiet.
521 }
522 }
523
524 /**
525 * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ThreadUtils.getAllThreads()}
526 * <p>
527 * This constructor is public to permit tools that require a JavaBean instance to operate.
528 * </p>
529 *
530 * @deprecated TODO Make private in 4.0.
531 */
532 @Deprecated
533 public ThreadUtils() {
534 // empty
535 }
536 }