    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
    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}