aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/lang3/ThreadUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/lang3/ThreadUtils.java')
-rw-r--r--src/main/java/org/apache/commons/lang3/ThreadUtils.java582
1 files changed, 582 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/lang3/ThreadUtils.java b/src/main/java/org/apache/commons/lang3/ThreadUtils.java
new file mode 100644
index 000000000..aa1250b3b
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/ThreadUtils.java
@@ -0,0 +1,582 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.time.DurationUtils;
+
+/**
+ * Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}.
+ *
+ * <p>
+ * #ThreadSafe#
+ * </p>
+ *
+ * @see Thread
+ * @see ThreadGroup
+ * @since 3.5
+ */
+public class ThreadUtils {
+
+ /**
+ * A predicate implementation which always returns true.
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate {
+
+ private AlwaysTruePredicate() {
+ }
+
+ @Override
+ public boolean test(final Thread thread) {
+ return true;
+ }
+
+ @Override
+ public boolean test(final ThreadGroup threadGroup) {
+ return true;
+ }
+ }
+
+ /**
+ * Used internally, consider private.
+ * <p>
+ * A predicate implementation which matches a thread or thread group name.
+ * </p>
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate {
+
+ private final String name;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param name thread or thread group name
+ * @throws NullPointerException if the name is {@code null}
+ */
+ public NamePredicate(final String name) {
+ Objects.requireNonNull(name, "name");
+ this.name = name;
+ }
+
+ @Override
+ public boolean test(final Thread thread) {
+ return thread != null && thread.getName().equals(name);
+ }
+
+ @Override
+ public boolean test(final ThreadGroup threadGroup) {
+ return threadGroup != null && threadGroup.getName().equals(name);
+ }
+ }
+
+ /**
+ * A predicate for selecting thread groups.
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ // When breaking BC, replace this with Predicate<ThreadGroup>
+ @FunctionalInterface
+ public interface ThreadGroupPredicate {
+
+ /**
+ * Evaluates this predicate on the given thread group.
+ * @param threadGroup the thread group
+ * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false}
+ */
+ boolean test(ThreadGroup threadGroup);
+ }
+
+ /**
+ * A predicate implementation which matches a thread id.
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ public static class ThreadIdPredicate implements ThreadPredicate {
+
+ private final long threadId;
+
+ /**
+ * Predicate constructor
+ *
+ * @param threadId the threadId to match
+ * @throws IllegalArgumentException if the threadId is zero or negative
+ */
+ public ThreadIdPredicate(final long threadId) {
+ if (threadId <= 0) {
+ throw new IllegalArgumentException("The thread id must be greater than zero");
+ }
+ this.threadId = threadId;
+ }
+
+ @Override
+ public boolean test(final Thread thread) {
+ return thread != null && thread.getId() == threadId;
+ }
+ }
+
+ /**
+ * A predicate for selecting threads.
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ // When breaking BC, replace this with Predicate<Thread>
+ @FunctionalInterface
+ public interface ThreadPredicate {
+
+ /**
+ * Evaluates this predicate on the given thread.
+ * @param thread the thread
+ * @return {@code true} if the thread matches the predicate, otherwise {@code false}
+ */
+ boolean test(Thread thread);
+ }
+
+ /**
+ * Predicate which always returns true.
+ *
+ * @deprecated Use a {@link Predicate}.
+ */
+ @Deprecated
+ public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate();
+
+ private static final Predicate<?> ALWAYS_TRUE = t -> true;
+
+ @SuppressWarnings("unchecked")
+ private static <T> Predicate<T> alwaysTruePredicate() {
+ return (Predicate<T>) ALWAYS_TRUE;
+ }
+
+ /**
+ * Finds the active thread with the specified id.
+ *
+ * @param threadId The thread id
+ * @return The thread with the specified id or {@code null} if no such thread exists
+ * @throws IllegalArgumentException if the specified id is zero or negative
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Thread findThreadById(final long threadId) {
+ if (threadId <= 0) {
+ throw new IllegalArgumentException("The thread id must be greater than zero");
+ }
+ final Collection<Thread> result = findThreads((Predicate<Thread>) t -> t != null && t.getId() == threadId);
+ return result.isEmpty() ? null : result.iterator().next();
+ }
+
+ /**
+ * Finds the active thread with the specified id if it belongs to a thread group with the specified group name.
+ *
+ * @param threadId The thread id
+ * @param threadGroupName The thread group name
+ * @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 no such thread exists
+ * @throws NullPointerException if the group name is null
+ * @throws IllegalArgumentException if the specified id is zero or negative
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Thread findThreadById(final long threadId, final String threadGroupName) {
+ Objects.requireNonNull(threadGroupName, "threadGroupName");
+ final Thread thread = findThreadById(threadId);
+ if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) {
+ return thread;
+ }
+ return null;
+ }
+
+ /**
+ * Finds the active thread with the specified id if it belongs to the specified thread group.
+ *
+ * @param threadId The thread id
+ * @param threadGroup The thread group
+ * @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 exists
+ * @throws NullPointerException if {@code threadGroup == null}
+ * @throws IllegalArgumentException if the specified id is zero or negative
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) {
+ Objects.requireNonNull(threadGroup, "threadGroup");
+ final Thread thread = findThreadById(threadId);
+ if (thread != null && threadGroup.equals(thread.getThreadGroup())) {
+ return thread;
+ }
+ return null;
+ }
+
+ /**
+ * Finds all active thread groups which match the given predicate.
+ *
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate
+ * @throws NullPointerException if the predicate is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @since 3.13.0
+ */
+ public static Collection<ThreadGroup> findThreadGroups(final Predicate<ThreadGroup> predicate) {
+ return findThreadGroups(getSystemThreadGroup(), true, predicate);
+ }
+
+ /**
+ * 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).
+ *
+ * @param threadGroup the thread group
+ * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group
+ * @throws NullPointerException if the given group or predicate is null
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @since 3.13.0
+ */
+ public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate<ThreadGroup> predicate) {
+ Objects.requireNonNull(threadGroup, "threadGroup");
+ Objects.requireNonNull(predicate, "predicate");
+
+ int count = threadGroup.activeGroupCount();
+ ThreadGroup[] threadGroups;
+ do {
+ threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size
+ count = threadGroup.enumerate(threadGroups, recurse);
+ //return value of enumerate() must be strictly less than the array size according to Javadoc
+ } while (count >= threadGroups.length);
+ return Collections.unmodifiableCollection(Stream.of(threadGroups).filter(predicate).collect(Collectors.toList()));
+ }
+
+ /**
+ * 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).
+ *
+ * @param threadGroup the thread group
+ * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group
+ * @throws NullPointerException if the given group or predicate is null
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}.
+ */
+ @Deprecated
+ public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) {
+ return findThreadGroups(threadGroup, recurse, (Predicate<ThreadGroup>) predicate::test);
+ }
+
+ /**
+ * Finds all active thread groups which match the given predicate.
+ *
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate
+ * @throws NullPointerException if the predicate is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @deprecated Use {@link #findThreadGroups(Predicate)}.
+ */
+ @Deprecated
+ public static Collection<ThreadGroup> findThreadGroups(final ThreadGroupPredicate predicate) {
+ return findThreadGroups(getSystemThreadGroup(), true, predicate);
+ }
+
+ /**
+ * Finds active thread groups with the specified group name.
+ *
+ * @param threadGroupName The thread group name
+ * @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.
+ * @throws NullPointerException if group name is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<ThreadGroup> findThreadGroupsByName(final String threadGroupName) {
+ return findThreadGroups(predicateThreadGroup(threadGroupName));
+ }
+
+ /**
+ * Finds all active threads which match the given predicate.
+ *
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active threads matching the given predicate
+ *
+ * @throws NullPointerException if the predicate is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @since 3.13.0
+ */
+ public static Collection<Thread> findThreads(final Predicate<Thread> predicate) {
+ return findThreads(getSystemThreadGroup(), true, predicate);
+ }
+
+ /**
+ * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
+ *
+ * @param threadGroup the thread group
+ * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group
+ * @throws NullPointerException if the given group or predicate is null
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @since 3.13.0
+ */
+ public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate<Thread> predicate) {
+ Objects.requireNonNull(threadGroup, "The group must not be null");
+ Objects.requireNonNull(predicate, "The predicate must not be null");
+ int count = threadGroup.activeCount();
+ Thread[] threads;
+ do {
+ threads = new Thread[count + count / 2 + 1]; //slightly grow the array size
+ count = threadGroup.enumerate(threads, recurse);
+ //return value of enumerate() must be strictly less than the array size according to javadoc
+ } while (count >= threads.length);
+ return Collections.unmodifiableCollection(Stream.of(threads).filter(predicate).collect(Collectors.toList()));
+ }
+
+ /**
+ * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups).
+ *
+ * @param threadGroup the thread group
+ * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group
+ * @throws NullPointerException if the given group or predicate is null
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}.
+ */
+ @Deprecated
+ public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) {
+ return findThreads(threadGroup, recurse, (Predicate<Thread>) predicate::test);
+ }
+
+ /**
+ * Finds all active threads which match the given predicate.
+ *
+ * @param predicate the predicate
+ * @return An unmodifiable {@link Collection} of active threads matching the given predicate
+ *
+ * @throws NullPointerException if the predicate is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ * @deprecated Use {@link #findThreads(Predicate)}.
+ */
+ @Deprecated
+ public static Collection<Thread> findThreads(final ThreadPredicate predicate) {
+ return findThreads(getSystemThreadGroup(), true, predicate);
+ }
+
+ /**
+ * Finds active threads with the specified name.
+ *
+ * @param threadName The thread name
+ * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable.
+ * @throws NullPointerException if the specified name is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<Thread> findThreadsByName(final String threadName) {
+ return findThreads(predicateThread(threadName));
+ }
+
+ /**
+ * Finds active threads with the specified name if they belong to a thread group with the specified group name.
+ *
+ * @param threadName The thread name
+ * @param threadGroupName The thread group name
+ * @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 returned if no such thread exists. The collection returned is always unmodifiable.
+ * @throws NullPointerException if the specified thread name or group name is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) {
+ Objects.requireNonNull(threadName, "threadName");
+ Objects.requireNonNull(threadGroupName, "threadGroupName");
+ return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream()
+ .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList()));
+ }
+
+ /**
+ * Finds active threads with the specified name if they belong to a specified thread group.
+ *
+ * @param threadName The thread name
+ * @param threadGroup The thread group
+ * @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 exists. The collection returned is always unmodifiable.
+ * @throws NullPointerException if the specified thread name or group is null
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<Thread> findThreadsByName(final String threadName, final ThreadGroup threadGroup) {
+ return findThreads(threadGroup, false, predicateThread(threadName));
+ }
+
+ /**
+ * Gets all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed).
+ *
+ * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable.
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<ThreadGroup> getAllThreadGroups() {
+ return findThreadGroups(alwaysTruePredicate());
+ }
+
+ /**
+ * Gets all active threads (A thread is active if it has been started and has not yet died).
+ *
+ * @return all active threads. The collection returned is always unmodifiable.
+ * @throws SecurityException
+ * if the current thread cannot access the system thread group
+ *
+ * @throws SecurityException if the current thread cannot modify
+ * thread groups from this thread's thread group up to the system thread group
+ */
+ public static Collection<Thread> getAllThreads() {
+ return findThreads(alwaysTruePredicate());
+ }
+
+ /**
+ * Gets the system thread group (sometimes also referred as "root thread group").
+ * <p>
+ * This method returns null if this thread has died (been stopped).
+ * </p>
+ *
+ * @return the system thread group
+ * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the
+ * system thread group
+ */
+ public static ThreadGroup getSystemThreadGroup() {
+ ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+ while (threadGroup != null && threadGroup.getParent() != null) {
+ threadGroup = threadGroup.getParent();
+ }
+ return threadGroup;
+ }
+
+ /**
+ * Waits for the given thread to die for the given duration. Implemented using {@link Thread#join(long, int)}.
+ *
+ * @param thread The thread to join.
+ * @param duration How long to wait.
+ * @throws InterruptedException if any thread has interrupted the current thread.
+ * @see Thread#join(long, int)
+ * @since 3.12.0
+ */
+ public static void join(final Thread thread, final Duration duration) throws InterruptedException {
+ DurationUtils.accept(thread::join, duration);
+ }
+
+ private static <T> Predicate<T> namePredicate(final String name, final Function<T, String> nameGetter) {
+ return (Predicate<T>) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name));
+ }
+
+ private static Predicate<Thread> predicateThread(final String threadName) {
+ return namePredicate(threadName, Thread::getName);
+ }
+
+ private static Predicate<ThreadGroup> predicateThreadGroup(final String threadGroupName) {
+ return namePredicate(threadGroupName, ThreadGroup::getName);
+ }
+
+ /**
+ * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}.
+ *
+ * @param duration How long to sleep.
+ * @throws InterruptedException if any thread has interrupted the current thread.
+ * @see Thread#sleep(long, int)
+ * @since 3.12.0
+ */
+ public static void sleep(final Duration duration) throws InterruptedException {
+ DurationUtils.accept(Thread::sleep, duration);
+ }
+
+ /**
+ * Sleeps for the given duration while ignoring {@link InterruptedException}.
+ * <p>
+ * The sleep duration may be shorter than duration if we catch a {@link InterruptedException}.
+ * </p>
+ *
+ * @param duration the length of time to sleep.
+ * @since 3.13.0
+ */
+ public static void sleepQuietly(final Duration duration) {
+ try {
+ sleep(duration);
+ } catch (final InterruptedException e) {
+ // be quiet.
+ }
+ }
+
+ /**
+ * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
+ * {@code ThreadUtils.getAllThreads()}
+ *
+ * <p>
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ * </p>
+ */
+ public ThreadUtils() {
+ }
+}