Add ThreadUtils

This commit is contained in:
Hendrik Saly 2015-05-04 00:16:31 +02:00
parent 8e7ea70a33
commit 6f653f6bb8
2 changed files with 831 additions and 0 deletions

View File

@ -0,0 +1,459 @@
/*
* 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;
/**
* <p>
* Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}.
* </p>
* <p>
* #ThreadSafe#
* </p>
*
* @see java.lang.Thread
* @see java.lang.ThreadGroup
* @since 3.5
* @version $Id$
*/
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 threadGroupName 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<Thread> 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<Thread> 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<Thread> result = new ArrayList<Thread>();
for(final ThreadGroup group : findThreadGroups(new NamePredicate(threadGroupName))) {
result.addAll(findThreads(group, false, new NamePredicate(threadName)));
}
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<ThreadGroup> 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<ThreadGroup> 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<Thread> 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<Thread> 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<Thread> result = findThreads(new ThreadIdPredicate(threadId));
if(!result.iterator().hasNext()) {
return null;
} else {
return result.iterator().next();
}
}
/**
* <p>
* ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
* {@code ThreadUtils.getAllThreads()}
* </p>
* <p>
* This constructor is public to permit tools that require a JavaBean instance to operate.
* </p>
*/
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 static interface ThreadPredicate /*extends java.util.function.Predicate<Thread>*/{
/**
* 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 static interface ThreadGroupPredicate /*extends java.util.function.Predicate<ThreadGroup>*/{
/**
* 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(@SuppressWarnings("unused") final ThreadGroup threadGroup) {
return true;
}
@Override
public boolean test(@SuppressWarnings("unused") 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<Thread> findThreads(final ThreadPredicate predicate){
return findThreads(getSystemThreadGroup(), true, predicate);
}
/**
* Select all active threadgroups which match the given predicate.
*
* @param 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<ThreadGroup> 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<Thread> 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");
}
final List<Thread> result = new ArrayList<Thread>();
int count = group.activeCount();
Thread[] threads;
do {
threads = new Thread[count + (count >> 1) + 1];
count = group.enumerate(threads, recurse);
} while (count >= threads.length);
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<ThreadGroup> 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");
}
final List<ThreadGroup> result = new ArrayList<ThreadGroup>();
int count = group.activeGroupCount();
ThreadGroup[] threadGroups;
do {
threadGroups = new ThreadGroup[count + (count>>1) + 1];
count = group.enumerate(threadGroups, recurse);
}
while(count >= threadGroups.length);
for(int i = 0; i<count; ++i) {
if(predicate.test(threadGroups[i])) {
result.add(threadGroups[i]);
}
}
return Collections.unmodifiableCollection(result);
}
}

View File

@ -0,0 +1,372 @@
/*
* 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
//import org.apache.commons.lang3.ThreadUtils.AlwaysTruePredicate;
import org.junit.Test;
/**
* Unit tests {@link org.apache.commons.lang3.ThreadUtils}.
*
* @version $Id$
*/
public class ThreadUtilsTest {
@Test(expected=IllegalArgumentException.class)
public void testNullThreadName() throws InterruptedException {
ThreadUtils.findThreadsByName(null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadGroupName() throws InterruptedException {
ThreadUtils.findThreadGroupsByName(null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroupName1() throws InterruptedException {
ThreadUtils.findThreadsByName(null, "tgname");
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroupName2() throws InterruptedException {
ThreadUtils.findThreadsByName("tname", (String) null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroupName3() throws InterruptedException {
ThreadUtils.findThreadsByName(null, (String) null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroup1() throws InterruptedException {
ThreadUtils.findThreadsByName("tname", (ThreadGroup) null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroup2() throws InterruptedException {
ThreadUtils.findThreadById(1L, (ThreadGroup) null);
}
@Test(expected=IllegalArgumentException.class)
public void testNullThreadThreadGroup3() throws InterruptedException {
ThreadUtils.findThreadsByName(null, (ThreadGroup) null);
}
@Test(expected=IllegalArgumentException.class)
public void testInvalidThreadId() throws InterruptedException {
ThreadUtils.findThreadById(-5L);
}
@Test(expected=IllegalArgumentException.class)
public void testThreadGroupsByIdFail() throws InterruptedException {
ThreadUtils.findThreadById(Thread.currentThread().getId(), (String) null);
}
@Test(expected=IllegalArgumentException.class)
public void testThreadgroupsNullParent() throws InterruptedException {
ThreadUtils.findThreadGroups(null, true, ThreadUtils.ALWAYS_TRUE_PREDICATE);
}
@Test(expected=IllegalArgumentException.class)
public void testThreadgroupsNullPredicate() throws InterruptedException {
ThreadUtils.findThreadGroups(null);
}
@Test(expected=IllegalArgumentException.class)
public void testThreadsNullPredicate() throws InterruptedException {
ThreadUtils.findThreads(null);
}
@Test
public void testNoThread() throws InterruptedException {
assertEquals(0, ThreadUtils.findThreadsByName("some_thread_which_does_not_exist_18762ZucTT").size());
}
@Test
public void testNoThreadGroup() throws InterruptedException {
assertEquals(0, ThreadUtils.findThreadGroupsByName("some_thread_group_which_does_not_exist_18762ZucTTII").size());
}
@Test
public void testSystemThreadGroupExists() throws InterruptedException {
final ThreadGroup systemThreadGroup = ThreadUtils.getSystemThreadGroup();
assertNotNull(systemThreadGroup);
assertNull(systemThreadGroup.getParent());
assertEquals("system", systemThreadGroup.getName());
}
@Test
public void testAtLeastOneThreadExists() throws InterruptedException {
assertTrue(ThreadUtils.getAllThreads().size() > 0);
}
@Test
public void testAtLeastOneThreadGroupsExists() throws InterruptedException {
assertTrue(ThreadUtils.getAllThreadGroups().size() > 0);
}
@Test
public void testThreadsSameName() throws InterruptedException {
final Thread t1 = new TestThread("thread1_XXOOLL__");
final Thread alsot1 = new TestThread("thread1_XXOOLL__");
try {
t1.start();
alsot1.start();
assertEquals(2, ThreadUtils.findThreadsByName("thread1_XXOOLL__").size());
} finally {
t1.interrupt();
alsot1.interrupt();
t1.join();
alsot1.join();
}
}
@Test
public void testThreads() throws InterruptedException {
final Thread t1 = new TestThread("thread1_XXOOLL__");
final Thread t2 = new TestThread("thread2_XXOOLL__");
try {
t1.start();
t2.start();
assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOLL__").size());
} finally {
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
}
}
@Test
public void testThreadsById() throws InterruptedException {
final Thread t1 = new TestThread("thread1_XXOOLL__");
final Thread t2 = new TestThread("thread2_XXOOLL__");
try {
t1.start();
t2.start();
assertEquals(t1.getName(), ThreadUtils.findThreadById(t1.getId()).getName());
assertSame(t2, ThreadUtils.findThreadById(t2.getId()));
} finally {
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
}
}
@Test
public void testThreadsByIdWrongGroup() throws InterruptedException {
final Thread t1 = new TestThread("thread1_XXOOLL__");
final ThreadGroup tg = new ThreadGroup("tg__HHEE22");
try {
t1.start();
assertNull(ThreadUtils.findThreadById(t1.getId(), tg));
} finally {
t1.interrupt();
t1.join();
tg.destroy();
}
}
@Test
public void testThreadGroups() throws InterruptedException {
final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
try {
t1.start();
t2.start();
assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__","thread_group_DDZZ99__").size());
assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__","thread_group_DDZZ99__").size());
assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__","non_existent_thread_group_JJHHZZ__").size());
assertEquals(0, ThreadUtils.findThreadsByName("non_existent_thread_BBDDWW__","thread_group_DDZZ99__").size());
assertEquals(1, ThreadUtils.findThreadGroupsByName("thread_group_DDZZ99__").size());
assertEquals(0, ThreadUtils.findThreadGroupsByName("non_existent_thread_group_JJHHZZ__").size());
assertNotNull(ThreadUtils.findThreadById(t1.getId(),threadGroup));
} finally {
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
threadGroup.destroy();
}
}
@Test
public void testThreadGroupsRef() throws InterruptedException {
final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
final ThreadGroup deadThreadGroup = new ThreadGroup("dead_thread_group_MMQQSS__");
deadThreadGroup.destroy();
final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
try {
t1.start();
t2.start();
assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__",threadGroup).size());
assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__",threadGroup).size());
assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__",deadThreadGroup).size());
} finally {
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
threadGroup.destroy();
assertEquals(0, ThreadUtils.findThreadsByName("thread2_XXOOPP__",threadGroup).size());
}
}
@Test
public void testThreadGroupsById() throws InterruptedException {
final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
final long nonExistingId = t1.getId()+t2.getId();
try {
t1.start();
t2.start();
assertEquals(t1.getName(), ThreadUtils.findThreadById(t1.getId(),"thread_group_DDZZ99__").getName());
assertEquals(t2.getName(), ThreadUtils.findThreadById(t2.getId(),"thread_group_DDZZ99__").getName());
assertNull(ThreadUtils.findThreadById(nonExistingId,"non_existent_thread_group_JJHHZZ__"));
assertNull(ThreadUtils.findThreadById(nonExistingId,"thread_group_DDZZ99__"));
} finally {
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
threadGroup.destroy();
}
}
@Test
public void testConstructor() throws InterruptedException {
assertNotNull(new ThreadUtils());
final Constructor<?>[] cons = ThreadUtils.class.getDeclaredConstructors();
assertEquals(1, cons.length);
assertTrue(Modifier.isPublic(cons[0].getModifiers()));
assertTrue(Modifier.isPublic(ThreadUtils.class.getModifiers()));
assertFalse(Modifier.isFinal(ThreadUtils.class.getModifiers()));
}
@Test
public void testComplexThreadGroups() throws Exception {
final ThreadGroup threadGroup1 = new ThreadGroup("thread_group_1__");
final ThreadGroup threadGroup2 = new ThreadGroup("thread_group_2__");
final ThreadGroup threadGroup3 = new ThreadGroup(threadGroup2, "thread_group_3__");
final ThreadGroup threadGroup4 = new ThreadGroup(threadGroup2, "thread_group_4__");
final ThreadGroup threadGroup5 = new ThreadGroup(threadGroup1, "thread_group_5__");
final ThreadGroup threadGroup6 = new ThreadGroup(threadGroup4, "thread_group_6__");
final List<ThreadGroup> threadGroups = Arrays.asList(threadGroup1,threadGroup2,threadGroup3,threadGroup4,threadGroup5,threadGroup6);
final Thread t1 = new TestThread("thread1_X__");
final Thread t2 = new TestThread(threadGroup1, "thread2_X__");
final Thread t3 = new TestThread(threadGroup2, "thread3_X__");
final Thread t4 = new TestThread(threadGroup3, "thread4_X__");
final Thread t5 = new TestThread(threadGroup4, "thread5_X__");
final Thread t6 = new TestThread(threadGroup5, "thread6_X__");
final Thread t7 = new TestThread(threadGroup6, "thread7_X__");
final Thread t8 = new TestThread(threadGroup4, "thread8_X__");
final Thread t9 = new TestThread(threadGroup6, "thread9_X__");
final Thread t10 = new TestThread(threadGroup3, "thread10_X__");
final List<Thread> threads = Arrays.asList(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10);
try {
for (final Iterator iterator = threads.iterator(); iterator.hasNext();) {
final Thread thread = (Thread) iterator.next();
thread.start();
}
assertTrue(ThreadUtils.getAllThreadGroups().size() >= 7);
assertTrue(ThreadUtils.getAllThreads().size() >= 11);
assertTrue(ThreadUtils.findThreads(ThreadUtils.ALWAYS_TRUE_PREDICATE).size() >= 11);
assertEquals(1, ThreadUtils.findThreadsByName(t4.getName(), threadGroup3.getName()).size());
assertEquals(0, ThreadUtils.findThreadsByName(t4.getName(), threadGroup2.getName()).size());
}finally {
for (final Iterator iterator = threads.iterator(); iterator.hasNext();) {
final Thread thread = (Thread) iterator.next();
thread.interrupt();
thread.join();
}
for (final Iterator iterator = threadGroups.iterator(); iterator.hasNext();) {
final ThreadGroup threadGroup = (ThreadGroup) iterator.next();
if(!threadGroup.isDestroyed())
threadGroup.destroy();
}
}
}
private static class TestThread extends Thread {
private final CountDownLatch latch = new CountDownLatch(1);
public TestThread(final String name) {
super(name);
}
public TestThread(final ThreadGroup group, final String name) {
super(group, name);
}
@Override
public synchronized void start() {
super.start();
try {
latch.await();
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void run() {
latch.countDown();
try {
synchronized(this){
this.wait();
}
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}