View Javadoc
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 }