diff --git a/src/main/java/org/apache/commons/lang3/ThreadUtils.java b/src/main/java/org/apache/commons/lang3/ThreadUtils.java index 1174ff7ad..15f0c5c05 100644 --- a/src/main/java/org/apache/commons/lang3/ThreadUtils.java +++ b/src/main/java/org/apache/commons/lang3/ThreadUtils.java @@ -1,466 +1,460 @@ -/* - * 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.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - *

- * Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}. - *

- *

- * #ThreadSafe# - *

- * - * @see java.lang.Thread - * @see java.lang.ThreadGroup - * @since 3.5 - */ -public class ThreadUtils { - - /** - * Return the active thread with the specified id if it belong's 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 IllegalArgumentException if the specified id is zero or negative or the 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 Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { - if (threadGroup == null) { - throw new IllegalArgumentException("The thread group must not be null"); - } - final Thread thread = findThreadById(threadId); - if(thread != null && threadGroup.equals(thread.getThreadGroup())) { - return thread; - } - return null; - } - - /** - * Return the active thread with the specified id if it belong's 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 IllegalArgumentException if the specified id is zero or negative or the 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 Thread findThreadById(final long threadId, final String threadGroupName) { - if (threadGroupName == null) { - throw new IllegalArgumentException("The thread group name must not be null"); - } - final Thread thread = findThreadById(threadId); - if(thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) { - return thread; - } - return null; - } - - /** - * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName, final ThreadGroup threadGroup) { - return findThreads(threadGroup, false, new NamePredicate(threadName)); - } - - /** - * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName, final String threadGroupName) { - if (threadName == null) { - throw new IllegalArgumentException("The thread name must not be null"); - } - if (threadGroupName == null) { - throw new IllegalArgumentException("The thread group name must not be null"); - } - - final Collection threadGroups = findThreadGroups(new NamePredicate(threadGroupName)); - - if(threadGroups.isEmpty()) { - return Collections.emptyList(); - } - - final Collection result = new ArrayList(); - final NamePredicate threadNamePredicate = new NamePredicate(threadName); - for(final ThreadGroup group : threadGroups) { - result.addAll(findThreads(group, false, threadNamePredicate)); - } - return Collections.unmodifiableCollection(result); - } - - /** - * Return 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 IllegalArgumentException 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 findThreadGroupsByName(final String threadGroupName) { - return findThreadGroups(new NamePredicate(threadGroupName)); - } - - /** - * Return 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 getAllThreadGroups() { - return findThreadGroups(ALWAYS_TRUE_PREDICATE); - } - - /** - * Return the system thread group (sometimes also referred as "root thread group"). - * - * @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.getParent() != null) { - threadGroup = threadGroup.getParent(); - } - return threadGroup; - } - - /** - * Return 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 getAllThreads() { - return findThreads(ALWAYS_TRUE_PREDICATE); - } - - /** - * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName) { - return findThreads(new NamePredicate(threadName)); - } - - /** - * Return 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) { - final Collection result = findThreads(new ThreadIdPredicate(threadId)); - - if(result.isEmpty()) { - return null; - } else { - return result.iterator().next(); - } - - } - - /** - *

- * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as - * {@code ThreadUtils.getAllThreads()} - *

- *

- * This constructor is public to permit tools that require a JavaBean instance to operate. - *

- */ - public ThreadUtils() { - super(); - } - - /** - * A predicate for selecting threads. - */ - //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate - public interface ThreadPredicate /*extends java.util.function.Predicate*/{ - - /** - * 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); - } - - /** - * A predicate for selecting threadgroups. - */ - //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate - public interface ThreadGroupPredicate /*extends java.util.function.Predicate*/{ - - /** - * Evaluates this predicate on the given threadgroup. - * @param threadGroup the threadgroup - * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false} - */ - boolean test(ThreadGroup threadGroup); - } - - /** - * Predicate which always returns true. - */ - public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); - - /** - * A predicate implementation which always returns true. - */ - private final static class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate{ - - private AlwaysTruePredicate() { - } - - @Override - public boolean test(final ThreadGroup threadGroup) { - return true; - } - - @Override - public boolean test(final Thread thread) { - return true; - } - } - - /** - * A predicate implementation which matches a thread or threadgroup name. - */ - public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { - - private final String name; - - /** - * Predicate constructor - * - * @param name thread or threadgroup name - * @throws IllegalArgumentException if the name is {@code null} - */ - public NamePredicate(final String name) { - super(); - if (name == null) { - throw new IllegalArgumentException("The name must not be null"); - } - this.name = name; - } - - @Override - public boolean test(final ThreadGroup threadGroup) { - return threadGroup != null && threadGroup.getName().equals(name); - } - - @Override - public boolean test(final Thread thread) { - return thread != null && thread.getName().equals(name); - } - } - - /** - * A predicate implementation which matches a thread id. - */ - 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) { - super(); - 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; - } - } - - /** - * Select all active threads which match the given predicate. - * - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threads matching the given predicate - * - * @throws IllegalArgumentException 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 - */ - public static Collection findThreads(final ThreadPredicate predicate){ - return findThreads(getSystemThreadGroup(), true, predicate); - } - - /** - * Select all active threadgroups which match the given predicate. - * - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threadgroups matching the given predicate - * @throws IllegalArgumentException 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 - */ - public static Collection findThreadGroups(final ThreadGroupPredicate predicate){ - return findThreadGroups(getSystemThreadGroup(), true, predicate); - } - - /** - * Select all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). - * - * @param group 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 {@code Collection} of active threads which match the given predicate and which belongs to the given thread group - * @throws IllegalArgumentException 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 - */ - public static Collection findThreads(final ThreadGroup group, final boolean recurse, final ThreadPredicate predicate) { - if (group == null) { - throw new IllegalArgumentException("The group must not be null"); - } - if (predicate == null) { - throw new IllegalArgumentException("The predicate must not be null"); - } - - int count = group.activeCount(); - Thread[] threads; - do { - threads = new Thread[count + (count / 2) + 1]; //slightly grow the array size - count = group.enumerate(threads, recurse); - //return value of enumerate() must be strictly less than the array size according to javadoc - } while (count >= threads.length); - - final List result = new ArrayList(count); - for (int i = 0; i < count; ++i) { - if (predicate.test(threads[i])) { - result.add(threads[i]); - } - } - return Collections.unmodifiableCollection(result); - } - - /** - * Select all active threadgroups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). - * - * @param group the thread group - * @param recurse if {@code true} then evaluate the predicate recursively on all threadgroups in all subgroups of the given group - * @param predicate the predicate - * @return An unmodifiable {@code Collection} of active threadgroups which match the given predicate and which is a subgroup of the given thread group - * @throws IllegalArgumentException 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 - */ - public static Collection findThreadGroups(final ThreadGroup group, final boolean recurse, final ThreadGroupPredicate predicate){ - if (group == null) { - throw new IllegalArgumentException("The group must not be null"); - } - if (predicate == null) { - throw new IllegalArgumentException("The predicate must not be null"); - } - - int count = group.activeGroupCount(); - ThreadGroup[] threadGroups; - do { - threadGroups = new ThreadGroup[count + (count / 2) + 1]; //slightly grow the array size - count = group.enumerate(threadGroups, recurse); - //return value of enumerate() must be strictly less than the array size according to javadoc - } while(count >= threadGroups.length); - - final List result = new ArrayList(count); - for(int i = 0; i < count; ++i) { - if(predicate.test(threadGroups[i])) { - result.add(threadGroups[i]); - } - } - return Collections.unmodifiableCollection(result); - } -} +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + *

+ * Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}. + *

+ *

+ * #ThreadSafe# + *

+ * + * @see java.lang.Thread + * @see java.lang.ThreadGroup + * @since 3.5 + */ +public class ThreadUtils { + + /** + * Return the active thread with the specified id if it belong's 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 IllegalArgumentException if the specified id is zero or negative or the 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 Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { + if (threadGroup == null) { + throw new IllegalArgumentException("The thread group must not be null"); + } + final Thread thread = findThreadById(threadId); + if(thread != null && threadGroup.equals(thread.getThreadGroup())) { + return thread; + } + return null; + } + + /** + * Return the active thread with the specified id if it belong's 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 IllegalArgumentException if the specified id is zero or negative or the 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 Thread findThreadById(final long threadId, final String threadGroupName) { + if (threadGroupName == null) { + throw new IllegalArgumentException("The thread group name must not be null"); + } + final Thread thread = findThreadById(threadId); + if(thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) { + return thread; + } + return null; + } + + /** + * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName, final ThreadGroup threadGroup) { + return findThreads(threadGroup, false, new NamePredicate(threadName)); + } + + /** + * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName, final String threadGroupName) { + if (threadName == null) { + throw new IllegalArgumentException("The thread name must not be null"); + } + if (threadGroupName == null) { + throw new IllegalArgumentException("The thread group name must not be null"); + } + + final Collection threadGroups = findThreadGroups(new NamePredicate(threadGroupName)); + + if(threadGroups.isEmpty()) { + return Collections.emptyList(); + } + + final Collection result = new ArrayList(); + final NamePredicate threadNamePredicate = new NamePredicate(threadName); + for(final ThreadGroup group : threadGroups) { + result.addAll(findThreads(group, false, threadNamePredicate)); + } + return Collections.unmodifiableCollection(result); + } + + /** + * Return 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 IllegalArgumentException 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 findThreadGroupsByName(final String threadGroupName) { + return findThreadGroups(new NamePredicate(threadGroupName)); + } + + /** + * Return 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 getAllThreadGroups() { + return findThreadGroups(ALWAYS_TRUE_PREDICATE); + } + + /** + * Return the system thread group (sometimes also referred as "root thread group"). + * + * @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.getParent() != null) { + threadGroup = threadGroup.getParent(); + } + return threadGroup; + } + + /** + * Return 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 getAllThreads() { + return findThreads(ALWAYS_TRUE_PREDICATE); + } + + /** + * Return 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 IllegalArgumentException 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 findThreadsByName(final String threadName) { + return findThreads(new NamePredicate(threadName)); + } + + /** + * Return 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) { + final Collection result = findThreads(new ThreadIdPredicate(threadId)); + return result.isEmpty() ? null : result.iterator().next(); + } + + /** + *

+ * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as + * {@code ThreadUtils.getAllThreads()} + *

+ *

+ * This constructor is public to permit tools that require a JavaBean instance to operate. + *

+ */ + public ThreadUtils() { + super(); + } + + /** + * A predicate for selecting threads. + */ + //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate + public interface ThreadPredicate /*extends java.util.function.Predicate*/{ + + /** + * 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); + } + + /** + * A predicate for selecting threadgroups. + */ + //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate + public interface ThreadGroupPredicate /*extends java.util.function.Predicate*/{ + + /** + * Evaluates this predicate on the given threadgroup. + * @param threadGroup the threadgroup + * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false} + */ + boolean test(ThreadGroup threadGroup); + } + + /** + * Predicate which always returns true. + */ + public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); + + /** + * A predicate implementation which always returns true. + */ + private final static class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate{ + + private AlwaysTruePredicate() { + } + + @Override + public boolean test(final ThreadGroup threadGroup) { + return true; + } + + @Override + public boolean test(final Thread thread) { + return true; + } + } + + /** + * A predicate implementation which matches a thread or threadgroup name. + */ + public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { + + private final String name; + + /** + * Predicate constructor + * + * @param name thread or threadgroup name + * @throws IllegalArgumentException if the name is {@code null} + */ + public NamePredicate(final String name) { + super(); + if (name == null) { + throw new IllegalArgumentException("The name must not be null"); + } + this.name = name; + } + + @Override + public boolean test(final ThreadGroup threadGroup) { + return threadGroup != null && threadGroup.getName().equals(name); + } + + @Override + public boolean test(final Thread thread) { + return thread != null && thread.getName().equals(name); + } + } + + /** + * A predicate implementation which matches a thread id. + */ + 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) { + super(); + 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; + } + } + + /** + * Select all active threads which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threads matching the given predicate + * + * @throws IllegalArgumentException 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 + */ + public static Collection findThreads(final ThreadPredicate predicate){ + return findThreads(getSystemThreadGroup(), true, predicate); + } + + /** + * Select all active threadgroups which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threadgroups matching the given predicate + * @throws IllegalArgumentException 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 + */ + public static Collection findThreadGroups(final ThreadGroupPredicate predicate){ + return findThreadGroups(getSystemThreadGroup(), true, predicate); + } + + /** + * Select all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). + * + * @param group 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 {@code Collection} of active threads which match the given predicate and which belongs to the given thread group + * @throws IllegalArgumentException 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 + */ + public static Collection findThreads(final ThreadGroup group, final boolean recurse, final ThreadPredicate predicate) { + if (group == null) { + throw new IllegalArgumentException("The group must not be null"); + } + if (predicate == null) { + throw new IllegalArgumentException("The predicate must not be null"); + } + + int count = group.activeCount(); + Thread[] threads; + do { + threads = new Thread[count + (count / 2) + 1]; //slightly grow the array size + count = group.enumerate(threads, recurse); + //return value of enumerate() must be strictly less than the array size according to javadoc + } while (count >= threads.length); + + final List result = new ArrayList(count); + for (int i = 0; i < count; ++i) { + if (predicate.test(threads[i])) { + result.add(threads[i]); + } + } + return Collections.unmodifiableCollection(result); + } + + /** + * Select all active threadgroups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). + * + * @param group the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all threadgroups in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threadgroups which match the given predicate and which is a subgroup of the given thread group + * @throws IllegalArgumentException 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 + */ + public static Collection findThreadGroups(final ThreadGroup group, final boolean recurse, final ThreadGroupPredicate predicate){ + if (group == null) { + throw new IllegalArgumentException("The group must not be null"); + } + if (predicate == null) { + throw new IllegalArgumentException("The predicate must not be null"); + } + + int count = group.activeGroupCount(); + ThreadGroup[] threadGroups; + do { + threadGroups = new ThreadGroup[count + (count / 2) + 1]; //slightly grow the array size + count = group.enumerate(threadGroups, recurse); + //return value of enumerate() must be strictly less than the array size according to javadoc + } while(count >= threadGroups.length); + + final List result = new ArrayList(count); + for(int i = 0; i < count; ++i) { + if(predicate.test(threadGroups[i])) { + result.add(threadGroups[i]); + } + } + return Collections.unmodifiableCollection(result); + } +}