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   * 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.hamcrest.MatcherAssert.assertThat;
23  import static org.hamcrest.Matchers.greaterThanOrEqualTo;
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.assertThrows;
30  import static org.junit.jupiter.api.Assertions.assertTrue;
31  
32  import java.lang.reflect.Constructor;
33  import java.lang.reflect.Modifier;
34  import java.time.Duration;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.List;
38  import java.util.Objects;
39  import java.util.concurrent.CountDownLatch;
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.junit.jupiter.api.Test;
45  
46  /**
47   * Unit tests {@link org.apache.commons.lang3.ThreadUtils}.
48   */
49  public 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      public void testAtLeastOneThreadExists() {
87          assertFalse(ThreadUtils.getAllThreads().isEmpty());
88      }
89  
90      @Test
91      public void testAtLeastOneThreadGroupsExists() {
92          assertFalse(ThreadUtils.getAllThreadGroups().isEmpty());
93      }
94  
95      @Test
96      public 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             assertThat("getAllThreadGroups", ThreadUtils.getAllThreadGroups().size(), greaterThanOrEqualTo(7));
127             assertThat("getAllThreads", ThreadUtils.getAllThreads().size(), greaterThanOrEqualTo(11));
128             assertThat("findThreads(ThreadUtils.ALWAYS_TRUE_PREDICATE)", ThreadUtils.findThreads(ThreadUtils.ALWAYS_TRUE_PREDICATE).size(), greaterThanOrEqualTo(11));
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     public 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     @Test
156     public void testGetAllThreadGroupsDoesNotReturnNull() {
157         // LANG-1706 getAllThreadGroups and findThreadGroups should not return null items
158         Collection<ThreadGroup> threads = ThreadUtils.getAllThreadGroups();
159         assertEquals(0, threads.stream().filter(Objects::isNull).count());
160     }
161 
162     @Test
163     public void testGetAllThreadsDoesNotReturnNull() {
164         // LANG-1706 getAllThreads and findThreads should not return null items
165         Collection<Thread> threads = ThreadUtils.getAllThreads();
166         assertEquals(0, threads.stream().filter(Objects::isNull).count());
167     }
168 
169     @Test
170     public void testInvalidThreadId() {
171         assertThrows(IllegalArgumentException.class, () -> ThreadUtils.findThreadById(-5L));
172     }
173 
174     @Test
175     public void testJoinDuration() throws InterruptedException {
176         ThreadUtils.join(new Thread(), Duration.ZERO);
177         ThreadUtils.join(new Thread(), Duration.ofMillis(1));
178     }
179 
180     @Test
181     public void testNoThread() {
182         assertEquals(0, ThreadUtils.findThreadsByName("some_thread_which_does_not_exist_18762ZucTT").size());
183     }
184 
185     @Test
186     public void testNoThreadGroup() {
187         assertEquals(0, ThreadUtils.findThreadGroupsByName("some_thread_group_which_does_not_exist_18762ZucTTII").size());
188     }
189 
190     @Test
191     public void testNullThreadGroupName() {
192         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroupsByName(null));
193     }
194 
195     @Test
196     public void testNullThreadName() {
197         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null));
198     }
199 
200     @Test
201     public void testNullThreadThreadGroup1() {
202         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName("tname", (ThreadGroup) null));
203     }
204 
205     @Test
206     public void testNullThreadThreadGroup2() {
207         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadById(1L, (ThreadGroup) null));
208     }
209 
210     @Test
211     public void testNullThreadThreadGroup3() {
212         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, (ThreadGroup) null));
213     }
214 
215     @Test
216     public void testNullThreadThreadGroupName1() {
217         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, "tgname"));
218     }
219 
220     @Test
221     public void testNullThreadThreadGroupName2() {
222         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName("tname", (String) null));
223     }
224 
225     @Test
226     public void testNullThreadThreadGroupName3() {
227         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadsByName(null, (String) null));
228     }
229 
230     @Test
231     public void testSleepDuration() throws InterruptedException {
232         ThreadUtils.sleep(Duration.ZERO);
233         ThreadUtils.sleep(Duration.ofMillis(1));
234     }
235 
236     @Test
237     public void testSystemThreadGroupExists() {
238         final ThreadGroup systemThreadGroup = ThreadUtils.getSystemThreadGroup();
239         assertNotNull(systemThreadGroup);
240         assertNull(systemThreadGroup.getParent());
241         assertEquals("system", systemThreadGroup.getName());
242     }
243 
244     @Test
245     public void testThreadGroups() throws InterruptedException {
246         final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroups";
247         final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
248         final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
249         final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
250 
251         try {
252             t1.start();
253             t2.start();
254             assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
255             assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroupName).size());
256             assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroupName).size());
257             assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", "non_existent_thread_group_JJHHZZ__").size());
258             assertEquals(0, ThreadUtils.findThreadsByName("non_existent_thread_BBDDWW__", threadGroupName).size());
259             assertEquals(1, ThreadUtils.findThreadGroupsByName(threadGroupName).size());
260             assertEquals(0, ThreadUtils.findThreadGroupsByName("non_existent_thread_group_JJHHZZ__").size());
261             assertNotNull(ThreadUtils.findThreadById(t1.getId(), threadGroup));
262         } finally {
263             t1.interrupt();
264             t2.interrupt();
265             t1.join();
266             t2.join();
267             threadGroup.destroy();
268         }
269     }
270 
271     @Test
272     public void testThreadGroupsById() throws InterruptedException {
273         final String threadGroupName = "thread_group_DDZZ99__for_testThreadGroupsById";
274         final ThreadGroup threadGroup = new ThreadGroup(threadGroupName);
275         final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
276         final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
277         final long nonExistingId = t1.getId() + t2.getId();
278 
279         try {
280             t1.start();
281             t2.start();
282             assertSame(t1, ThreadUtils.findThreadById(t1.getId(), threadGroupName));
283             assertSame(t2, ThreadUtils.findThreadById(t2.getId(), threadGroupName));
284             assertNull(ThreadUtils.findThreadById(nonExistingId, "non_existent_thread_group_JJHHZZ__"));
285             assertNull(ThreadUtils.findThreadById(nonExistingId, threadGroupName));
286         } finally {
287             t1.interrupt();
288             t2.interrupt();
289             t1.join();
290             t2.join();
291             threadGroup.destroy();
292         }
293     }
294 
295     @Test
296     public void testThreadGroupsByIdFail() {
297         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadById(Thread.currentThread().getId(), (String) null));
298     }
299 
300     @Test
301     public void testThreadGroupsNullParent() {
302         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, true, ThreadUtils.ALWAYS_TRUE_PREDICATE));
303         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, false, ThreadUtils.ALWAYS_TRUE_PREDICATE));
304     }
305 
306     @Test
307     public void testThreadGroupsNullPredicate() {
308         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((ThreadGroupPredicate) null));
309         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate<ThreadGroup>) null));
310         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate) null));
311     }
312 
313     @Test
314     public void testThreadGroupsRef() throws InterruptedException {
315         final ThreadGroup threadGroup = new ThreadGroup("thread_group_DDZZ99__");
316         final ThreadGroup deadThreadGroup = new ThreadGroup("dead_thread_group_MMQQSS__");
317         deadThreadGroup.destroy();
318         final Thread t1 = new TestThread(threadGroup, "thread1_XXOOPP__");
319         final Thread t2 = new TestThread(threadGroup, "thread2_XXOOPP__");
320 
321         try {
322             t1.start();
323             t2.start();
324             assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__").size());
325             assertEquals(1, ThreadUtils.findThreadsByName("thread1_XXOOPP__", threadGroup).size());
326             assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
327             assertEquals(0, ThreadUtils.findThreadsByName("thread1_XXOOPP__", deadThreadGroup).size());
328         } finally {
329             t1.interrupt();
330             t2.interrupt();
331             t1.join();
332             t2.join();
333             threadGroup.destroy();
334             assertEquals(0, ThreadUtils.findThreadsByName("thread2_XXOOPP__", threadGroup).size());
335         }
336     }
337 
338     @Test
339     public void testThreads() throws InterruptedException {
340         final Thread t1 = new TestThread("thread1_XXOOLL__");
341         final Thread t2 = new TestThread("thread2_XXOOLL__");
342 
343         try {
344             t1.start();
345             t2.start();
346             assertEquals(1, ThreadUtils.findThreadsByName("thread2_XXOOLL__").size());
347         } finally {
348             t1.interrupt();
349             t2.interrupt();
350             t1.join();
351             t2.join();
352         }
353     }
354 
355     @Test
356     public void testThreadsById() throws InterruptedException {
357         final Thread t1 = new TestThread("thread1_XXOOLL__");
358         final Thread t2 = new TestThread("thread2_XXOOLL__");
359 
360         try {
361             t1.start();
362             t2.start();
363             assertSame(t1, ThreadUtils.findThreadById(t1.getId()));
364             assertSame(t2, ThreadUtils.findThreadById(t2.getId()));
365         } finally {
366             t1.interrupt();
367             t2.interrupt();
368             t1.join();
369             t2.join();
370         }
371     }
372 
373     @Test
374     public void testThreadsByIdWrongGroup() throws InterruptedException {
375         final Thread t1 = new TestThread("thread1_XXOOLL__");
376         final ThreadGroup tg = new ThreadGroup("tg__HHEE22");
377 
378         try {
379             t1.start();
380             assertNull(ThreadUtils.findThreadById(t1.getId(), tg));
381         } finally {
382             t1.interrupt();
383             t1.join();
384             tg.destroy();
385         }
386     }
387 
388     @Test
389     public void testThreadsNullPredicate() {
390         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((ThreadPredicate) null));
391         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate<Thread>) null));
392         assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate) null));
393     }
394 
395     @Test
396     public void testThreadsSameName() throws InterruptedException {
397         final Thread t1 = new TestThread("thread1_XXOOLL__");
398         final Thread alsot1 = new TestThread("thread1_XXOOLL__");
399 
400         try {
401             t1.start();
402             alsot1.start();
403             assertEquals(2, ThreadUtils.findThreadsByName("thread1_XXOOLL__").size());
404         } finally {
405             t1.interrupt();
406             alsot1.interrupt();
407             t1.join();
408             alsot1.join();
409         }
410     }
411 
412 }