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