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