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}