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