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    *      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  
51          private AlwaysTruePredicate() {
52          }
53  
54          @Override
55          public boolean test(final Thread thread) {
56              return true;
57          }
58  
59          @Override
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           */
84          public NamePredicate(final String name) {
85              Objects.requireNonNull(name, "name");
86              this.name = name;
87          }
88  
89          @Override
90          public boolean test(final Thread thread) {
91              return thread != null && thread.getName().equals(name);
92          }
93  
94          @Override
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          */
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          */
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
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          */
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")
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      */
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      */
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      */
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      */
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      */
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).limit(count).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
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
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      */
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      */
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      */
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).limit(count).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
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
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      */
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      */
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      */
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      */
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      */
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      */
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      */
527     public static void join(final Thread thread, final Duration duration) throws InterruptedException {
528         DurationUtils.accept(thread::join, duration);
529     }
530 
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 
535     private static Predicate<Thread> predicateThread(final String threadName) {
536         return namePredicate(threadName, Thread::getName);
537     }
538 
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      */
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      */
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      */
580     public ThreadUtils() {
581     }
582 }