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 *      https://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.function.Predicates;
029import org.apache.commons.lang3.time.DurationUtils;
030
031/**
032 * Helpers for {@link Thread} and {@link ThreadGroup}.
033 *
034 * <p>
035 * #ThreadSafe#
036 * </p>
037 *
038 * @see Thread
039 * @see ThreadGroup
040 * @since 3.5
041 */
042public class ThreadUtils {
043
044    /**
045     * A predicate implementation which always returns true.
046     *
047     * @deprecated Use a {@link Predicate}.
048     */
049    @Deprecated
050    private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate {
051
052        private AlwaysTruePredicate() {
053        }
054
055        @Override
056        public boolean test(final Thread thread) {
057            return true;
058        }
059
060        @Override
061        public boolean test(final ThreadGroup threadGroup) {
062            return true;
063        }
064    }
065
066    /**
067     * Used internally, consider private.
068     * <p>
069     * A predicate implementation which matches a thread or thread group name.
070     * </p>
071     *
072     * @deprecated Use a {@link Predicate}.
073     */
074    @Deprecated
075    public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate {
076
077        private final String name;
078
079        /**
080         * Constructs an instance.
081         *
082         * @param name thread or thread group name.
083         * @throws NullPointerException if the name is {@code null}.
084         */
085        public NamePredicate(final String name) {
086            Objects.requireNonNull(name, "name");
087            this.name = name;
088        }
089
090        @Override
091        public boolean test(final Thread thread) {
092            return thread != null && thread.getName().equals(name);
093        }
094
095        @Override
096        public boolean test(final ThreadGroup threadGroup) {
097            return threadGroup != null && threadGroup.getName().equals(name);
098        }
099    }
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}