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.ofMillis(1));
190 ThreadUtils.join(new Thread(), Duration.ofMillis(2));
191 }
192
193 @Test
194 void testJoinDurationZero() throws InterruptedException {
195
196 ThreadUtils.join(new Thread(), Duration.ZERO);
197 }
198
199 @Test
200 void testNoThread() {
201 assertEquals(0, ThreadUtils.findThreadsByName("some_thread_which_does_not_exist_18762ZucTT").size());
202 }
203
204 @Test
205 void testNoThreadGroup() {
206 assertEquals(0, ThreadUtils.findThreadGroupsByName("some_thread_group_which_does_not_exist_18762ZucTTII").size());
207 }
208
209 @Test
210 void testNullThreadGroupName() {
211 assertNullPointerException(() -> ThreadUtils.findThreadGroupsByName(null));
212 }
213
214 @Test
215 void testNullThreadName() {
216 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null));
217 }
218
219 @Test
220 void testNullThreadThreadGroup1() {
221 assertNullPointerException(() -> ThreadUtils.findThreadsByName("tname", (ThreadGroup) null));
222 }
223
224 @Test
225 void testNullThreadThreadGroup2() {
226 assertNullPointerException(() -> ThreadUtils.findThreadById(1L, (ThreadGroup) null));
227 }
228
229 @Test
230 void testNullThreadThreadGroup3() {
231 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, (ThreadGroup) null));
232 }
233
234 @Test
235 void testNullThreadThreadGroupName1() {
236 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, "tgname"));
237 }
238
239 @Test
240 void testNullThreadThreadGroupName2() {
241 assertNullPointerException(() -> ThreadUtils.findThreadsByName("tname", (String) null));
242 }
243
244 @Test
245 void testNullThreadThreadGroupName3() {
246 assertNullPointerException(() -> ThreadUtils.findThreadsByName(null, (String) null));
247 }
248
249 @Test
250 void testSleepDuration() throws InterruptedException {
251 ThreadUtils.sleep(Duration.ZERO);
252 ThreadUtils.sleep(Duration.ofMillis(1));
253 }
254
255 @Test
256 void testSleepQuietlyInterruptDuringSleep() throws Exception {
257 final AtomicBoolean isInterrupted = new AtomicBoolean();
258 final Thread testThread = new Thread(() -> {
259
260 ThreadUtils.sleepQuietly(Duration.ofSeconds(10));
261 isInterrupted.set(Thread.currentThread().isInterrupted());
262 });
263 testThread.start();
264 Thread.sleep(100);
265 testThread.interrupt();
266 testThread.join(1000);
267 assertTrue(isInterrupted.get(), "Interrupted flag should be preserved after InterruptedException");
268 }
269
270 @Test
271 void testSleepQuietlyInterruptedFlagPreserved() {
272 Thread.currentThread().interrupt();
273
274 ThreadUtils.sleepQuietly(Duration.ofMillis(1000));
275 assertTrue(Thread.interrupted(), "Interrupted flag should be preserved");
276 }
277
278 @Test
279 void testSleepQuietlyNormalNoInterrupt() {
280 Thread.interrupted();
281 ThreadUtils.sleepQuietly(Duration.ofMillis(10));
282 assertFalse(Thread.currentThread().isInterrupted(), "Interrupted flag should not be set for normal sleep");
283 }
284
285 @Test
286 void testSystemThreadGroupExists() {
287 final ThreadGroup systemThreadGroup = ThreadUtils.getSystemThreadGroup();
288 assertNotNull(systemThreadGroup);
289 assertNull(systemThreadGroup.getParent());
290 assertEquals("system", systemThreadGroup.getName());
291 }
292
293 @Test
294 void testThreadGroups() throws InterruptedException {
295 final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroups";
296 final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
297 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
298 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
299
300 try {
301 t1.start();
302 t2.start();
303 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
304 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroupName).size());
305 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroupName).size());
306 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", "non_existent_thread_group_JJHHZZ__").size());
307 assertEquals(0, ThreadUtils.findThreadsByName("non_existent_thread_BBDDWW__", threadGroupName).size());
308 assertEquals(1, ThreadUtils.findThreadGroupsByName(threadGroupName).size());
309 assertEquals(0, ThreadUtils.findThreadGroupsByName("non_existent_thread_group_JJHHZZ__").size());
310 assertNotNull(ThreadUtils.findThreadById(t1.getId(), threadGroup));
311 } finally {
312 t1.interrupt();
313 t2.interrupt();
314 t1.join();
315 t2.join();
316 threadGroup.destroy();
317 }
318 }
319
320 @Test
321 void testThreadGroupsById() throws InterruptedException {
322 final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroupsById";
323 final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
324 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
325 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
326 final long nonExistingId = t1.getId() + t2.getId();
327
328 try {
329 t1.start();
330 t2.start();
331 assertSame(t1, ThreadUtils.findThreadById(t1.getId(), threadGroupName));
332 assertSame(t2, ThreadUtils.findThreadById(t2.getId(), threadGroupName));
333 assertNull(ThreadUtils.findThreadById(nonExistingId, "non_existent_thread_group_JJHHZZ__"));
334 assertNull(ThreadUtils.findThreadById(nonExistingId, threadGroupName));
335 } finally {
336 t1.interrupt();
337 t2.interrupt();
338 t1.join();
339 t2.join();
340 threadGroup.destroy();
341 }
342 }
343
344 @Test
345 void testThreadGroupsByIdFail() {
346 assertNullPointerException(() -> ThreadUtils.findThreadById(Thread.currentThread().getId(), (String) null));
347 }
348
349 @Test
350 void testThreadGroupsNullParent() {
351 assertNullPointerException(() -> ThreadUtils.findThreadGroups(null, true, Predicates.truePredicate()));
352 assertNullPointerException(() -> ThreadUtils.findThreadGroups(null, false, Predicates.truePredicate()));
353 }
354
355 @Test
356 void testThreadGroupsNullPredicate() {
357 assertNullPointerException(() -> ThreadUtils.findThreadGroups((ThreadGroupPredicate) null));
358 assertNullPointerException(() -> ThreadUtils.findThreadGroups((Predicate<ThreadGroup>) null));
359 assertNullPointerException(() -> ThreadUtils.findThreadGroups((Predicate) null));
360 }
361
362 @Test
363 void testThreadGroupsRef() throws InterruptedException {
364 final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
365 final ThreadGroup deadThreadGroup = new ThreadGroup("dead_thread_group_MMQQSS__");
366 deadThreadGroup.destroy();
367 final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
368 final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
369
370 try {
371 t1.start();
372 t2.start();
373 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
374 assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroup).size());
375 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
376 assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", deadThreadGroup).size());
377 } finally {
378 t1.interrupt();
379 t2.interrupt();
380 t1.join();
381 t2.join();
382 threadGroup.destroy();
383 assertEquals(0, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
384 }
385 }
386
387 @Test
388 void testThreads() throws InterruptedException {
389 final Thread t1 = new TestThread("thread1_XXOOLL__");
390 final Thread t2 = new TestThread("thread2_XXOOLL__");
391
392 try {
393 t1.start();
394 t2.start();
395 assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOLL__").size());
396 } finally {
397 t1.interrupt();
398 t2.interrupt();
399 t1.join();
400 t2.join();
401 }
402 }
403
404 @Test
405 void testThreadsById() throws InterruptedException {
406 final Thread t1 = new TestThread("thread1_XXOOLL__");
407 final Thread t2 = new TestThread("thread2_XXOOLL__");
408
409 try {
410 t1.start();
411 t2.start();
412 assertSame(t1, ThreadUtils.findThreadById(t1.getId()));
413 assertSame(t2, ThreadUtils.findThreadById(t2.getId()));
414 } finally {
415 t1.interrupt();
416 t2.interrupt();
417 t1.join();
418 t2.join();
419 }
420 }
421
422 @Test
423 void testThreadsByIdWrongGroup() throws InterruptedException {
424 final Thread t1 = new TestThread("thread1_XXOOLL__");
425 final ThreadGroup tg = new ThreadGroup("tg__HHEE22");
426
427 try {
428 t1.start();
429 assertNull(ThreadUtils.findThreadById(t1.getId(), tg));
430 } finally {
431 t1.interrupt();
432 t1.join();
433 tg.destroy();
434 }
435 }
436
437 @Test
438 void testThreadsNullPredicate() {
439 assertNullPointerException(() -> ThreadUtils.findThreads((ThreadPredicate) null));
440 assertNullPointerException(() -> ThreadUtils.findThreads((Predicate<Thread>) null));
441 assertNullPointerException(() -> ThreadUtils.findThreads((Predicate) null));
442 }
443
444 @Test
445 void testThreadsSameName() throws InterruptedException {
446 final Thread t1 = new TestThread("thread1_XXOOLL__");
447 final Thread alsot1 = new TestThread("thread1_XXOOLL__");
448
449 try {
450 t1.start();
451 alsot1.start();
452 assertEquals(2, ThreadUtils.findThreadsByName("thread1_XXOOLL__").size());
453 } finally {
454 t1.interrupt();
455 alsot1.interrupt();
456 t1.join();
457 alsot1.join();
458 }
459 }
460
461 }