1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.lang3;
21
22 import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
23 import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 import static org.junit.jupiter.api.Assertions.assertFalse;
26 import static org.junit.jupiter.api.Assertions.assertNotNull;
27 import static org.junit.jupiter.api.Assertions.assertNull;
28 import static org.junit.jupiter.api.Assertions.assertSame;
29 import static org.junit.jupiter.api.Assertions.assertTrue;
30
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.Modifier;
33 import java.time.Duration;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.List;
37 import java.util.Objects;
38 import java.util.concurrent.CountDownLatch;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.function.Predicate;
41
42 import org.apache.commons.lang3.ThreadUtils.ThreadGroupPredicate;
43 import org.apache.commons.lang3.ThreadUtils.ThreadPredicate;
44 import org.apache.commons.lang3.function.Predicates;
45 import org.junit.jupiter.api.Test;
46
47
48
49
50 class ThreadUtilsTest extends AbstractLangTest {
51
52 private static final class TestThread extends Thread {
53 private final CountDownLatch latch = new CountDownLatch(1);
54
55 TestThread(final String name) {
56 super(name);
57 }
58
59 TestThread(final ThreadGroup group, final String name) {
60 super(group, name);
61 }
62
63 @Override
64 public void run() {
65 latch.countDown();
66 try {
67 synchronized (this) {
68 this.wait();
69 }
70 } catch (final InterruptedException e) {
71 Thread.currentThread().interrupt();
72 }
73 }
74
75 @Override
76 public synchronized void start() {
77 super.start();
78 try {
79 latch.await();
80 } catch (final InterruptedException e) {
81 Thread.currentThread().interrupt();
82 }
83 }
84 }
85
86 @Test
87 void testAtLeastOneThreadExists() {
88 assertFalse(ThreadUtils.getAllThreads().isEmpty());
89 }
90
91 @Test
92 void testAtLeastOneThreadGroupsExists() {
93 assertFalse(ThreadUtils.getAllThreadGroups().isEmpty());
94 }
95
96 @Test
97 void testComplexThreadGroups() throws Exception {
98 final ThreadGroup threadGroup1 = new ThreadGroup("thread_group_1__");
99 final ThreadGroup threadGroup2 = new ThreadGroup("thread_group_2__");
100 final ThreadGroup threadGroup3 = new ThreadGroup(threadGroup2, "thread_group_3__");
101 final ThreadGroup threadGroup4 = new ThreadGroup(threadGroup2, "thread_group_4__");
102 final ThreadGroup threadGroup5 = new ThreadGroup(threadGroup1, "thread_group_5__");
103 final ThreadGroup threadGroup6 = new ThreadGroup(threadGroup4, "thread_group_6__");
104 final ThreadGroup threadGroup7 = new ThreadGroup(threadGroup4, "thread_group_7__");
105 final ThreadGroup threadGroup7Doubled = new ThreadGroup(threadGroup4, "thread_group_7__");
106 final List<ThreadGroup> threadGroups = Arrays.asList(threadGroup1, threadGroup2, threadGroup3, threadGroup4, threadGroup5, threadGroup6, threadGroup7,
107 threadGroup7Doubled);
108
109 final Thread t1 = new TestThread("thread1_X__");
110 final Thread t2 = new TestThread(threadGroup1, "thread2_X__");
111 final Thread t3 = new TestThread(threadGroup2, "thread3_X__");
112 final Thread t4 = new TestThread(threadGroup3, "thread4_X__");
113 final Thread t5 = new TestThread(threadGroup4, "thread5_X__");
114 final Thread t6 = new TestThread(threadGroup5, "thread6_X__");
115 final Thread t7 = new TestThread(threadGroup6, "thread7_X__");
116 final Thread t8 = new TestThread(threadGroup4, "thread8_X__");
117 final Thread t9 = new TestThread(threadGroup6, "thread9_X__");
118 final Thread t10 = new TestThread(threadGroup3, "thread10_X__");
119 final Thread t11 = new TestThread(threadGroup7, "thread11_X__");
120 final Thread t11Doubled = new TestThread(threadGroup7Doubled, "thread11_X__");
121 final List<Thread> threads = Arrays.asList(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t11Doubled);
122
123 try {
124 for (final Thread thread : threads) {
125 thread.start();
126 }
127 assertTrue(ThreadUtils.getAllThreadGroups().size() >= 7, "getAllThreadGroups");
128 assertTrue(ThreadUtils.getAllThreads().size() >= 11, "getAllThreads");
129 assertTrue(ThreadUtils.findThreads(Predicates.truePredicate()).size() >= 11, "findThreads(ThreadUtils.truePredicate())");
130 assertEquals(1, ThreadUtils.findThreadsByName(t4.getName(), threadGroup3.getName()).size());
131 assertEquals(0, ThreadUtils.findThreadsByName(t4.getName(), threadGroup2.getName()).size());
132 assertEquals(2, ThreadUtils.findThreadsByName(t11.getName(), threadGroup7.getName()).size());
133 } finally {
134 for (final Thread thread : threads) {
135 thread.interrupt();
136 thread.join();
137 }
138 for (final ThreadGroup threadGroup : threadGroups) {
139 if (!threadGroup.isDestroyed()) {
140 threadGroup.destroy();
141 }
142 }
143 }
144 }
145
146 @Test
147 void testConstructor() {
148 assertNotNull(new ThreadUtils());
149 final Constructor<?>[] cons = ThreadUtils.class.getDeclaredConstructors();
150 assertEquals(1, cons.length);
151 assertTrue(Modifier.isPublic(cons[0].getModifiers()));
152 assertTrue(Modifier.isPublic(ThreadUtils.class.getModifiers()));
153 assertFalse(Modifier.isFinal(ThreadUtils.class.getModifiers()));
154 }
155
156 @SuppressWarnings("deprecation")
157 @Test
158 void testDepreacted() {
159 assertNotNull(ThreadUtils.ALWAYS_TRUE_PREDICATE);
160 final ThreadPredicate tp = ThreadUtils.ALWAYS_TRUE_PREDICATE;
161 assertTrue(tp.test(null));
162 assertTrue(tp.test(new Thread()));
163 final ThreadGroupPredicate tgp = ThreadUtils.ALWAYS_TRUE_PREDICATE;
164 assertTrue(tgp.test(null));
165 assertTrue(tgp.test(new ThreadGroup("")));
166 }
167
168 @Test
169 void testGetAllThreadGroupsDoesNotReturnNull() {
170
171 final Collection<ThreadGroup> threads = ThreadUtils.getAllThreadGroups();
172 assertEquals(0, threads.stream().filter(Objects::isNull).count());
173 }
174
175 @Test
176 void testGetAllThreadsDoesNotReturnNull() {
177
178 final Collection<Thread> threads = ThreadUtils.getAllThreads();
179 assertEquals(0, threads.stream().filter(Objects::isNull).count());
180 }
181
182 @Test
183 void testInvalidThreadId() {
184 assertIllegalArgumentException(() -> ThreadUtils.findThreadById(-5L));
185 }
186
187 @Test
188 void testJoinDuration() throws InterruptedException {
189 ThreadUtils.join(new Thread(), Duration.ZERO);
190 ThreadUtils.join(new Thread(), Duration.ofMillis(1));
191 }
192
193 @Test
194 void testNoThread() {
195 assertEquals(0, ThreadUtils.findThreadsByName("some_thread_which_does_not_exist_18762ZucTT").size());
196 }
197
198 @Test
199 void testNoThreadGroup() {
200 assertEquals(0, ThreadUtils.findThreadGroupsByName("some_thread_group_which_does_not_exist_18762ZucTTII").size());
201 }
202
203 @Test
204 void testNullThreadGroupName() {
205 assertNullPointerException(() -> ThreadUtils.findThreadGroupsByName(null));
206 }
207
208 @Test
209 void testNullThreadName() {
210 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null));
211 }
212
213 @Test
214 void testNullThreadThreadGroup1() {
215 assertNullPointerException(() -> ThreadUtils.findThreadsByName("tname", (ThreadGroup) null));
216 }
217
218 @Test
219 void testNullThreadThreadGroup2() {
220 assertNullPointerException(() -> ThreadUtils.findThreadById(1L, (ThreadGroup) null));
221 }
222
223 @Test
224 void testNullThreadThreadGroup3() {
225 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, (ThreadGroup) null));
226 }
227
228 @Test
229 void testNullThreadThreadGroupName1() {
230 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, "tgname"));
231 }
232
233 @Test
234 void testNullThreadThreadGroupName2() {
235 assertNullPointerException(() -> ThreadUtils.findThreadsByName("tname", (String) null));
236 }
237
238 @Test
239 void testNullThreadThreadGroupName3() {
240 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, (String) null));
241 }
242
243 @Test
244 void testSleepDuration() throws InterruptedException {
245 ThreadUtils.sleep(Duration.ZERO);
246 ThreadUtils.sleep(Duration.ofMillis(1));
247 }
248
249 @Test
250 void testSleepQuietlyInterruptDuringSleep() throws Exception {
251 final AtomicBoolean isInterrupted = new AtomicBoolean();
252 final Thread testThread = new Thread(() -> {
253
254 ThreadUtils.sleepQuietly(Duration.ofSeconds(10));
255 isInterrupted.set(Thread.currentThread().isInterrupted());
256 });
257 testThread.start();
258 Thread.sleep(100);
259 testThread.interrupt();
260 testThread.join(1000);
261 assertTrue(isInterrupted.get(), "Interrupted flag should be preserved after InterruptedException");
262 }
263
264 @Test
265 void testSleepQuietlyInterruptedFlagPreserved() {
266 Thread.currentThread().interrupt();
267
268 ThreadUtils.sleepQuietly(Duration.ofMillis(1000));
269 assertTrue(Thread.interrupted(), "Interrupted flag should be preserved");
270 }
271
272 @Test
273 void testSleepQuietlyNormalNoInterrupt() {
274 Thread.interrupted();
275 ThreadUtils.sleepQuietly(Duration.ofMillis(10));
276 assertFalse(Thread.currentThread().isInterrupted(), "Interrupted flag should not be set for normal sleep");
277 }
278
279 @Test
280 void testSystemThreadGroupExists() {
281 final ThreadGroup systemThreadGroup = ThreadUtils.getSystemThreadGroup();
282 assertNotNull(systemThreadGroup);
283 assertNull(systemThreadGroup.getParent());
284 assertEquals("system", systemThreadGroup.getName());
285 }
286
287 @Test
288 void testThreadGroups() throws InterruptedException {
289 final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroups";
290 final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
291 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
292 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
293
294 try {
295 t1.start();
296 t2.start();
297 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
298 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroupName).size());
299 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroupName).size());
300 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", "non_existent_thread_group_JJHHZZ__").size());
301 assertEquals(0, ThreadUtils.findThreadsByName("non_existent_thread_BBDDWW__", threadGroupName).size());
302 assertEquals(1, ThreadUtils.findThreadGroupsByName(threadGroupName).size());
303 assertEquals(0, ThreadUtils.findThreadGroupsByName("non_existent_thread_group_JJHHZZ__").size());
304 assertNotNull(ThreadUtils.findThreadById(t1.getId(), threadGroup));
305 } finally {
306 t1.interrupt();
307 t2.interrupt();
308 t1.join();
309 t2.join();
310 threadGroup.destroy();
311 }
312 }
313
314 @Test
315 void testThreadGroupsById() throws InterruptedException {
316 final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroupsById";
317 final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
318 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
319 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
320 final long nonExistingId = t1.getId() + t2.getId();
321
322 try {
323 t1.start();
324 t2.start();
325 assertSame(t1, ThreadUtils.findThreadById(t1.getId(), threadGroupName));
326 assertSame(t2, ThreadUtils.findThreadById(t2.getId(), threadGroupName));
327 assertNull(ThreadUtils.findThreadById(nonExistingId, "non_existent_thread_group_JJHHZZ__"));
328 assertNull(ThreadUtils.findThreadById(nonExistingId, threadGroupName));
329 } finally {
330 t1.interrupt();
331 t2.interrupt();
332 t1.join();
333 t2.join();
334 threadGroup.destroy();
335 }
336 }
337
338 @Test
339 void testThreadGroupsByIdFail() {
340 assertNullPointerException(() -> ThreadUtils.findThreadById(Thread.currentThread().getId(), (String) null));
341 }
342
343 @Test
344 void testThreadGroupsNullParent() {
345 assertNullPointerException(() -> ThreadUtils.findThreadGroups(null, true, Predicates.truePredicate()));
346 assertNullPointerException(() -> ThreadUtils.findThreadGroups(null, false, Predicates.truePredicate()));
347 }
348
349 @Test
350 void testThreadGroupsNullPredicate() {
351 assertNullPointerException(() -> ThreadUtils.findThreadGroups((ThreadGroupPredicate) null));
352 assertNullPointerException(() -> ThreadUtils.findThreadGroups((Predicate<ThreadGroup>) null));
353 assertNullPointerException(() -> ThreadUtils.findThreadGroups((Predicate) null));
354 }
355
356 @Test
357 void testThreadGroupsRef() throws InterruptedException {
358 final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
359 final ThreadGroup deadThreadGroup = new ThreadGroup("dead_thread_group_MMQQSS__");
360 deadThreadGroup.destroy();
361 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
362 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
363
364 try {
365 t1.start();
366 t2.start();
367 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
368 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroup).size());
369 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
370 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", deadThreadGroup).size());
371 } finally {
372 t1.interrupt();
373 t2.interrupt();
374 t1.join();
375 t2.join();
376 threadGroup.destroy();
377 assertEquals(0, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
378 }
379 }
380
381 @Test
382 void testThreads() throws InterruptedException {
383 final Thread t1 = new TestThread("thread1_XXOOLL__");
384 final Thread t2 = new TestThread("thread2_XXOOLL__");
385
386 try {
387 t1.start();
388 t2.start();
389 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOLL__").size());
390 } finally {
391 t1.interrupt();
392 t2.interrupt();
393 t1.join();
394 t2.join();
395 }
396 }
397
398 @Test
399 void testThreadsById() throws InterruptedException {
400 final Thread t1 = new TestThread("thread1_XXOOLL__");
401 final Thread t2 = new TestThread("thread2_XXOOLL__");
402
403 try {
404 t1.start();
405 t2.start();
406 assertSame(t1, ThreadUtils.findThreadById(t1.getId()));
407 assertSame(t2, ThreadUtils.findThreadById(t2.getId()));
408 } finally {
409 t1.interrupt();
410 t2.interrupt();
411 t1.join();
412 t2.join();
413 }
414 }
415
416 @Test
417 void testThreadsByIdWrongGroup() throws InterruptedException {
418 final Thread t1 = new TestThread("thread1_XXOOLL__");
419 final ThreadGroup tg = new ThreadGroup("tg__HHEE22");
420
421 try {
422 t1.start();
423 assertNull(ThreadUtils.findThreadById(t1.getId(), tg));
424 } finally {
425 t1.interrupt();
426 t1.join();
427 tg.destroy();
428 }
429 }
430
431 @Test
432 void testThreadsNullPredicate() {
433 assertNullPointerException(() -> ThreadUtils.findThreads((ThreadPredicate) null));
434 assertNullPointerException(() -> ThreadUtils.findThreads((Predicate<Thread>) null));
435 assertNullPointerException(() -> ThreadUtils.findThreads((Predicate) null));
436 }
437
438 @Test
439 void testThreadsSameName() throws InterruptedException {
440 final Thread t1 = new TestThread("thread1_XXOOLL__");
441 final Thread alsot1 = new TestThread("thread1_XXOOLL__");
442
443 try {
444 t1.start();
445 alsot1.start();
446 assertEquals(2, ThreadUtils.findThreadsByName("thread1_XXOOLL__").size());
447 } finally {
448 t1.interrupt();
449 alsot1.interrupt();
450 t1.join();
451 alsot1.join();
452 }
453 }
454
455 }