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}