1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 package org.apache.commons.lang3; 21 22 import static org.junit.jupiter.api.Assertions.assertEquals; 23 import static org.junit.jupiter.api.Assertions.assertFalse; 24 import static org.junit.jupiter.api.Assertions.assertNotNull; 25 import static org.junit.jupiter.api.Assertions.assertNull; 26 import static org.junit.jupiter.api.Assertions.assertSame; 27 import static org.junit.jupiter.api.Assertions.assertThrows; 28 import static org.junit.jupiter.api.Assertions.assertTrue; 29 30 import java.lang.reflect.Constructor; 31 import java.lang.reflect.Modifier; 32 import java.time.Duration; 33 import java.util.Arrays; 34 import java.util.List; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.function.Predicate; 37 38 import org.apache.commons.lang3.ThreadUtils.ThreadGroupPredicate; 39 import org.apache.commons.lang3.ThreadUtils.ThreadPredicate; 40 import org.junit.jupiter.api.Test; 41 42 /** 43 * Unit tests {@link org.apache.commons.lang3.ThreadUtils}. 44 */ 45 public class ThreadUtilsTest extends AbstractLangTest { 46 47 private static class TestThread extends Thread { 48 private final CountDownLatch latch = new CountDownLatch(1); 49 TestThread(final String name)50 TestThread(final String name) { 51 super(name); 52 } 53 TestThread(final ThreadGroup group, final String name)54 TestThread(final ThreadGroup group, final String name) { 55 super(group, name); 56 } 57 58 @Override run()59 public void run() { 60 latch.countDown(); 61 try { 62 synchronized (this) { 63 this.wait(); 64 } 65 } catch (final InterruptedException e) { 66 Thread.currentThread().interrupt(); 67 } 68 } 69 70 @Override start()71 public synchronized void start() { 72 super.start(); 73 try { 74 latch.await(); 75 } catch (final InterruptedException e) { 76 Thread.currentThread().interrupt(); 77 } 78 } 79 } 80 81 @Test testAtLeastOneThreadExists()82 public void testAtLeastOneThreadExists() { 83 assertFalse(ThreadUtils.getAllThreads().isEmpty()); 84 } 85 86 @Test testAtLeastOneThreadGroupsExists()87 public void testAtLeastOneThreadGroupsExists() { 88 assertFalse(ThreadUtils.getAllThreadGroups().isEmpty()); 89 } 90 91 @Test testComplexThreadGroups()92 public void testComplexThreadGroups() throws Exception { 93 final ThreadGroup threadGroup1 = new ThreadGroup("thread_group_1__"); 94 final ThreadGroup threadGroup2 = new ThreadGroup("thread_group_2__"); 95 final ThreadGroup threadGroup3 = new ThreadGroup(threadGroup2, "thread_group_3__"); 96 final ThreadGroup threadGroup4 = new ThreadGroup(threadGroup2, "thread_group_4__"); 97 final ThreadGroup threadGroup5 = new ThreadGroup(threadGroup1, "thread_group_5__"); 98 final ThreadGroup threadGroup6 = new ThreadGroup(threadGroup4, "thread_group_6__"); 99 final ThreadGroup threadGroup7 = new ThreadGroup(threadGroup4, "thread_group_7__"); 100 final ThreadGroup threadGroup7Doubled = new ThreadGroup(threadGroup4, "thread_group_7__"); 101 final List<ThreadGroup> threadGroups = Arrays.asList(threadGroup1, threadGroup2, threadGroup3, threadGroup4, threadGroup5, threadGroup6, threadGroup7, 102 threadGroup7Doubled); 103 104 final Thread t1 = new TestThread("thread1_X__"); 105 final Thread t2 = new TestThread(threadGroup1, "thread2_X__"); 106 final Thread t3 = new TestThread(threadGroup2, "thread3_X__"); 107 final Thread t4 = new TestThread(threadGroup3, "thread4_X__"); 108 final Thread t5 = new TestThread(threadGroup4, "thread5_X__"); 109 final Thread t6 = new TestThread(threadGroup5, "thread6_X__"); 110 final Thread t7 = new TestThread(threadGroup6, "thread7_X__"); 111 final Thread t8 = new TestThread(threadGroup4, "thread8_X__"); 112 final Thread t9 = new TestThread(threadGroup6, "thread9_X__"); 113 final Thread t10 = new TestThread(threadGroup3, "thread10_X__"); 114 final Thread t11 = new TestThread(threadGroup7, "thread11_X__"); 115 final Thread t11Doubled = new TestThread(threadGroup7Doubled, "thread11_X__"); 116 final List<Thread> threads = Arrays.asList(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t11Doubled); 117 118 try { 119 for (final Thread thread : threads) { 120 thread.start(); 121 } 122 assertTrue(ThreadUtils.getAllThreadGroups().size() >= 7); 123 assertTrue(ThreadUtils.getAllThreads().size() >= 11); 124 assertTrue(ThreadUtils.findThreads(ThreadUtils.ALWAYS_TRUE_PREDICATE).size() >= 11); 125 assertEquals(1, ThreadUtils.findThreadsByName(t4.getName(), threadGroup3.getName()).size()); 126 assertEquals(0, ThreadUtils.findThreadsByName(t4.getName(), threadGroup2.getName()).size()); 127 assertEquals(2, ThreadUtils.findThreadsByName(t11.getName(), threadGroup7.getName()).size()); 128 } finally { 129 for (final Thread thread : threads) { 130 thread.interrupt(); 131 thread.join(); 132 } 133 for (final ThreadGroup threadGroup : threadGroups) { 134 if (!threadGroup.isDestroyed()) { 135 threadGroup.destroy(); 136 } 137 } 138 } 139 } 140 141 @Test testConstructor()142 public void testConstructor() { 143 assertNotNull(new ThreadUtils()); 144 final Constructor<?>[] cons = ThreadUtils.class.getDeclaredConstructors(); 145 assertEquals(1, cons.length); 146 assertTrue(Modifier.isPublic(cons[0].getModifiers())); 147 assertTrue(Modifier.isPublic(ThreadUtils.class.getModifiers())); 148 assertFalse(Modifier.isFinal(ThreadUtils.class.getModifiers())); 149 } 150 151 @Test testInvalidThreadId()152 public void testInvalidThreadId() { 153 assertThrows(IllegalArgumentException.class, () -> ThreadUtils.findThreadById(-5L)); 154 } 155 156 @Test testJoinDuration()157 public void testJoinDuration() throws InterruptedException { 158 ThreadUtils.join(new Thread(), Duration.ZERO); 159 ThreadUtils.join(new Thread(), Duration.ofMillis(1)); 160 } 161 162 @Test testNoThread()163 public void testNoThread() { 164 assertEquals(0, ThreadUtils.findThreadsByName("some_thread_which_does_not_exist_18762ZucTT").size()); 165 } 166 167 @Test testNoThreadGroup()168 public void testNoThreadGroup() { 169 assertEquals(0, ThreadUtils.findThreadGroupsByName("some_thread_group_which_does_not_exist_18762ZucTTII").size()); 170 } 171 172 @Test testNullThreadGroupName()173 public void testNullThreadGroupName() { 174 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroupsByName(null)); 175 } 176 177 @Test testNullThreadName()178 public void testNullThreadName() { 179 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null)); 180 } 181 182 @Test testNullThreadThreadGroup1()183 public void testNullThreadThreadGroup1() { 184 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName("tname", (ThreadGroup) null)); 185 } 186 187 @Test testNullThreadThreadGroup2()188 public void testNullThreadThreadGroup2() { 189 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadById(1L, (ThreadGroup) null)); 190 } 191 192 @Test testNullThreadThreadGroup3()193 public void testNullThreadThreadGroup3() { 194 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, (ThreadGroup) null)); 195 } 196 197 @Test testNullThreadThreadGroupName1()198 public void testNullThreadThreadGroupName1() { 199 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, "tgname")); 200 } 201 202 @Test testNullThreadThreadGroupName2()203 public void testNullThreadThreadGroupName2() { 204 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName("tname", (String) null)); 205 } 206 207 @Test testNullThreadThreadGroupName3()208 public void testNullThreadThreadGroupName3() { 209 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, (String) null)); 210 } 211 212 @Test testSleepDuration()213 public void testSleepDuration() throws InterruptedException { 214 ThreadUtils.sleep(Duration.ZERO); 215 ThreadUtils.sleep(Duration.ofMillis(1)); 216 } 217 218 @Test testSystemThreadGroupExists()219 public void testSystemThreadGroupExists() { 220 final ThreadGroup systemThreadGroup = ThreadUtils.getSystemThreadGroup(); 221 assertNotNull(systemThreadGroup); 222 assertNull(systemThreadGroup.getParent()); 223 assertEquals("system", systemThreadGroup.getName()); 224 } 225 226 @Test testThreadGroups()227 public void testThreadGroups() throws InterruptedException { 228 final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__"); 229 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__"); 230 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__"); 231 232 try { 233 t1.start(); 234 t2.start(); 235 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size()); 236 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", "thread_group_DDZZ99__").size()); 237 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", "thread_group_DDZZ99__").size()); 238 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", "non_existent_thread_group_JJHHZZ__").size()); 239 assertEquals(0, ThreadUtils.findThreadsByName("non_existent_thread_BBDDWW__", "thread_group_DDZZ99__").size()); 240 assertEquals(1, ThreadUtils.findThreadGroupsByName("thread_group_DDZZ99__").size()); 241 assertEquals(0, ThreadUtils.findThreadGroupsByName("non_existent_thread_group_JJHHZZ__").size()); 242 assertNotNull(ThreadUtils.findThreadById(t1.getId(), threadGroup)); 243 } finally { 244 t1.interrupt(); 245 t2.interrupt(); 246 t1.join(); 247 t2.join(); 248 threadGroup.destroy(); 249 } 250 } 251 252 @Test testThreadGroupsById()253 public void testThreadGroupsById() throws InterruptedException { 254 final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__"); 255 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__"); 256 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__"); 257 final long nonExistingId = t1.getId() + t2.getId(); 258 259 try { 260 t1.start(); 261 t2.start(); 262 assertSame(t1, ThreadUtils.findThreadById(t1.getId(), "thread_group_DDZZ99__")); 263 assertSame(t2, ThreadUtils.findThreadById(t2.getId(), "thread_group_DDZZ99__")); 264 assertNull(ThreadUtils.findThreadById(nonExistingId, "non_existent_thread_group_JJHHZZ__")); 265 assertNull(ThreadUtils.findThreadById(nonExistingId, "thread_group_DDZZ99__")); 266 } finally { 267 t1.interrupt(); 268 t2.interrupt(); 269 t1.join(); 270 t2.join(); 271 threadGroup.destroy(); 272 } 273 } 274 275 @Test testThreadGroupsByIdFail()276 public void testThreadGroupsByIdFail() { 277 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadById(Thread.currentThread().getId(), (String) null)); 278 } 279 280 @Test testThreadGroupsNullParent()281 public void testThreadGroupsNullParent() { 282 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, true, ThreadUtils.ALWAYS_TRUE_PREDICATE)); 283 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, false, ThreadUtils.ALWAYS_TRUE_PREDICATE)); 284 } 285 286 @Test testThreadGroupsNullPredicate()287 public void testThreadGroupsNullPredicate() { 288 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((ThreadGroupPredicate) null)); 289 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate<ThreadGroup>) null)); 290 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate) null)); 291 } 292 293 @Test testThreadGroupsRef()294 public void testThreadGroupsRef() throws InterruptedException { 295 final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__"); 296 final ThreadGroup deadThreadGroup = new ThreadGroup("dead_thread_group_MMQQSS__"); 297 deadThreadGroup.destroy(); 298 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__"); 299 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__"); 300 301 try { 302 t1.start(); 303 t2.start(); 304 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size()); 305 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroup).size()); 306 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size()); 307 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", deadThreadGroup).size()); 308 } finally { 309 t1.interrupt(); 310 t2.interrupt(); 311 t1.join(); 312 t2.join(); 313 threadGroup.destroy(); 314 assertEquals(0, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size()); 315 } 316 } 317 318 @Test testThreads()319 public void testThreads() throws InterruptedException { 320 final Thread t1 = new TestThread("thread1_XXOOLL__"); 321 final Thread t2 = new TestThread("thread2_XXOOLL__"); 322 323 try { 324 t1.start(); 325 t2.start(); 326 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOLL__").size()); 327 } finally { 328 t1.interrupt(); 329 t2.interrupt(); 330 t1.join(); 331 t2.join(); 332 } 333 } 334 335 @Test testThreadsById()336 public void testThreadsById() throws InterruptedException { 337 final Thread t1 = new TestThread("thread1_XXOOLL__"); 338 final Thread t2 = new TestThread("thread2_XXOOLL__"); 339 340 try { 341 t1.start(); 342 t2.start(); 343 assertSame(t1, ThreadUtils.findThreadById(t1.getId())); 344 assertSame(t2, ThreadUtils.findThreadById(t2.getId())); 345 } finally { 346 t1.interrupt(); 347 t2.interrupt(); 348 t1.join(); 349 t2.join(); 350 } 351 } 352 353 @Test testThreadsByIdWrongGroup()354 public void testThreadsByIdWrongGroup() throws InterruptedException { 355 final Thread t1 = new TestThread("thread1_XXOOLL__"); 356 final ThreadGroup tg = new ThreadGroup("tg__HHEE22"); 357 358 try { 359 t1.start(); 360 assertNull(ThreadUtils.findThreadById(t1.getId(), tg)); 361 } finally { 362 t1.interrupt(); 363 t1.join(); 364 tg.destroy(); 365 } 366 } 367 368 @Test testThreadsNullPredicate()369 public void testThreadsNullPredicate() { 370 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((ThreadPredicate) null)); 371 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate<Thread>) null)); 372 assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate) null)); 373 } 374 375 @Test testThreadsSameName()376 public void testThreadsSameName() throws InterruptedException { 377 final Thread t1 = new TestThread("thread1_XXOOLL__"); 378 final Thread alsot1 = new TestThread("thread1_XXOOLL__"); 379 380 try { 381 t1.start(); 382 alsot1.start(); 383 assertEquals(2, ThreadUtils.findThreadsByName("thread1_XXOOLL__").size()); 384 } finally { 385 t1.interrupt(); 386 alsot1.interrupt(); 387 t1.join(); 388 alsot1.join(); 389 } 390 } 391 } 392