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