001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.time.Duration;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.Objects;
023import java.util.function.Function;
024import java.util.function.Predicate;
025import java.util.stream.Collectors;
026import java.util.stream.Stream;
027
028import org.apache.commons.lang3.time.DurationUtils;
029
030/**
031 * Helpers for {@link Thread} and {@link ThreadGroup}.
032 *
033 * <p>
034 * #ThreadSafe#
035 * </p>
036 *
037 * @see Thread
038 * @see ThreadGroup
039 * @since 3.5
040 */
041public class ThreadUtils {
042
043    /**
044     * A predicate implementation which always returns true.
045     *
046     * @deprecated Use a {@link Predicate}.
047     */
048    @Deprecated
049    private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate {
050
051        private AlwaysTruePredicate() {
052        }
053
054        @Override
055        public boolean test(final Thread thread) {
056            return true;
057        }
058
059        @Override
060        public boolean test(final ThreadGroup threadGroup) {
061            return true;
062        }
063    }
064
065    /**
066     * Used internally, consider private.
067     * <p>
068     * A predicate implementation which matches a thread or thread group name.
069     * </p>
070     *
071     * @deprecated Use a {@link Predicate}.
072     */
073    @Deprecated
074    public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate {
075
076        private final String name;
077
078        /**
079         * Constructs an instance.
080         *
081         * @param name thread or thread group name
082         * @throws NullPointerException if the name is {@code null}
083         */
084        public NamePredicate(final String name) {
085            Objects.requireNonNull(name, "name");
086            this.name = name;
087        }
088
089        @Override
090        public boolean test(final Thread thread) {
091            return thread != null && thread.getName().equals(name);
092        }
093
094        @Override
095        public boolean test(final ThreadGroup threadGroup) {
096            return threadGroup != null && threadGroup.getName().equals(name);
097        }
098    }
099
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 ignore) {
568            // Ignore & be quiet.
569        }
570    }
571
572    /**
573     * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ThreadUtils.getAllThreads()}
574     * <p>
575     * This constructor is public to permit tools that require a JavaBean instance to operate.
576     * </p>
577     *
578     * @deprecated TODO Make private in 4.0.
579     */
580    @Deprecated
581    public ThreadUtils() {
582        // empty
583    }
584}