Source code
Description: source: package: org.apache.commons.lang3, class: ThreadUtils, class: ThreadIdPredicate

    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}