001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.time.Duration; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.Objects; 023import java.util.function.Function; 024import java.util.function.Predicate; 025import java.util.stream.Collectors; 026import java.util.stream.Stream; 027 028import org.apache.commons.lang3.function.Predicates; 029import org.apache.commons.lang3.time.DurationUtils; 030 031/** 032 * Helpers for {@link Thread} and {@link ThreadGroup}. 033 * 034 * <p> 035 * #ThreadSafe# 036 * </p> 037 * 038 * @see Thread 039 * @see ThreadGroup 040 * @since 3.5 041 */ 042public class ThreadUtils { 043 044 /** 045 * A predicate implementation which always returns true. 046 * 047 * @deprecated Use a {@link Predicate}. 048 */ 049 @Deprecated 050 private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate { 051 052 private AlwaysTruePredicate() { 053 } 054 055 @Override 056 public boolean test(final Thread thread) { 057 return true; 058 } 059 060 @Override 061 public boolean test(final ThreadGroup threadGroup) { 062 return true; 063 } 064 } 065 066 /** 067 * Used internally, consider private. 068 * <p> 069 * A predicate implementation which matches a thread or thread group name. 070 * </p> 071 * 072 * @deprecated Use a {@link Predicate}. 073 */ 074 @Deprecated 075 public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { 076 077 private final String name; 078 079 /** 080 * Constructs an instance. 081 * 082 * @param name thread or thread group name 083 * @throws NullPointerException if the name is {@code null} 084 */ 085 public NamePredicate(final String name) { 086 Objects.requireNonNull(name, "name"); 087 this.name = name; 088 } 089 090 @Override 091 public boolean test(final Thread thread) { 092 return thread != null && thread.getName().equals(name); 093 } 094 095 @Override 096 public boolean test(final ThreadGroup threadGroup) { 097 return threadGroup != null && threadGroup.getName().equals(name); 098 } 099 } 100 101 /** 102 * A predicate for selecting thread groups. 103 * 104 * @deprecated Use a {@link Predicate}. 105 */ 106 @Deprecated 107 // When breaking BC, replace this with Predicate<ThreadGroup> 108 @FunctionalInterface 109 public interface ThreadGroupPredicate { 110 111 /** 112 * Evaluates this predicate on the given thread group. 113 * @param threadGroup the thread group 114 * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false} 115 */ 116 boolean test(ThreadGroup threadGroup); 117 } 118 119 /** 120 * A predicate implementation which matches a thread id. 121 * 122 * @deprecated Use a {@link Predicate}. 123 */ 124 @Deprecated 125 public static class ThreadIdPredicate implements ThreadPredicate { 126 127 private final long threadId; 128 129 /** 130 * Predicate constructor 131 * 132 * @param threadId the threadId to match 133 * @throws IllegalArgumentException if the threadId is zero or negative 134 */ 135 public ThreadIdPredicate(final long threadId) { 136 if (threadId <= 0) { 137 throw new IllegalArgumentException("The thread id must be greater than zero"); 138 } 139 this.threadId = threadId; 140 } 141 142 @Override 143 public boolean test(final Thread thread) { 144 return thread != null && thread.getId() == threadId; 145 } 146 } 147 148 /** 149 * A predicate for selecting threads. 150 * 151 * @deprecated Use a {@link Predicate}. 152 */ 153 @Deprecated 154 // When breaking BC, replace this with Predicate<Thread> 155 @FunctionalInterface 156 public interface ThreadPredicate { 157 158 /** 159 * Evaluates this predicate on the given thread. 160 * @param thread the thread 161 * @return {@code true} if the thread matches the predicate, otherwise {@code false} 162 */ 163 boolean test(Thread thread); 164 } 165 166 /** 167 * Predicate which always returns true. 168 * 169 * @deprecated Use a {@link Predicate}. 170 */ 171 @Deprecated 172 public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); 173 174 /** 175 * Finds the active thread with the specified id. 176 * 177 * @param threadId The thread id 178 * @return The thread with the specified id or {@code null} if no such thread exists 179 * @throws IllegalArgumentException if the specified id is zero or negative 180 * @throws SecurityException 181 * if the current thread cannot access the system thread group 182 * @throws SecurityException if the current thread cannot modify 183 * thread groups from this thread's thread group up to the system thread group 184 */ 185 public static Thread findThreadById(final long threadId) { 186 if (threadId <= 0) { 187 throw new IllegalArgumentException("The thread id must be greater than zero"); 188 } 189 final Collection<Thread> result = findThreads((Predicate<Thread>) t -> t != null && t.getId() == threadId); 190 return result.isEmpty() ? null : result.iterator().next(); 191 } 192 193 /** 194 * Finds the active thread with the specified id if it belongs to a thread group with the specified group name. 195 * 196 * @param threadId The thread id 197 * @param threadGroupName The thread group name 198 * @return The threads which belongs to a thread group with the specified group name and the thread's id match the specified id. 199 * {@code null} is returned if no such thread exists 200 * @throws NullPointerException if the group name is null 201 * @throws IllegalArgumentException if the specified id is zero or negative 202 * @throws SecurityException 203 * if the current thread cannot access the system thread group 204 * 205 * @throws SecurityException if the current thread cannot modify 206 * thread groups from this thread's thread group up to the system thread group 207 */ 208 public static Thread findThreadById(final long threadId, final String threadGroupName) { 209 Objects.requireNonNull(threadGroupName, "threadGroupName"); 210 final Thread thread = findThreadById(threadId); 211 if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) { 212 return thread; 213 } 214 return null; 215 } 216 217 /** 218 * Finds the active thread with the specified id if it belongs to the specified thread group. 219 * 220 * @param threadId The thread id 221 * @param threadGroup The thread group 222 * @return The thread which belongs to a specified thread group and the thread's id match the specified id. 223 * {@code null} is returned if no such thread exists 224 * @throws NullPointerException if {@code threadGroup == null} 225 * @throws IllegalArgumentException if the specified id is zero or negative 226 * @throws SecurityException 227 * if the current thread cannot access the system thread group 228 * 229 * @throws SecurityException if the current thread cannot modify 230 * thread groups from this thread's thread group up to the system thread group 231 */ 232 public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { 233 Objects.requireNonNull(threadGroup, "threadGroup"); 234 final Thread thread = findThreadById(threadId); 235 if (thread != null && threadGroup.equals(thread.getThreadGroup())) { 236 return thread; 237 } 238 return null; 239 } 240 241 /** 242 * Finds all active thread groups which match the given predicate. 243 * 244 * @param predicate the predicate 245 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate 246 * @throws NullPointerException if the predicate is null 247 * @throws SecurityException 248 * if the current thread cannot access the system thread group 249 * @throws SecurityException if the current thread cannot modify 250 * thread groups from this thread's thread group up to the system thread group 251 * @since 3.13.0 252 */ 253 public static Collection<ThreadGroup> findThreadGroups(final Predicate<ThreadGroup> predicate) { 254 return findThreadGroups(getSystemThreadGroup(), true, predicate); 255 } 256 257 /** 258 * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). 259 * 260 * @param threadGroup the thread group 261 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group 262 * @param predicate the predicate 263 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group 264 * @throws NullPointerException if the given group or predicate is null 265 * @throws SecurityException if the current thread cannot modify 266 * thread groups from this thread's thread group up to the system thread group 267 * @since 3.13.0 268 */ 269 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate<ThreadGroup> predicate) { 270 Objects.requireNonNull(threadGroup, "threadGroup"); 271 Objects.requireNonNull(predicate, "predicate"); 272 int count = threadGroup.activeGroupCount(); 273 ThreadGroup[] threadGroups; 274 do { 275 threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size 276 count = threadGroup.enumerate(threadGroups, recurse); 277 //return value of enumerate() must be strictly less than the array size according to Javadoc 278 } while (count >= threadGroups.length); 279 return Collections.unmodifiableCollection(Stream.of(threadGroups).limit(count).filter(predicate).collect(Collectors.toList())); 280 } 281 282 /** 283 * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). 284 * 285 * @param threadGroup the thread group 286 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group 287 * @param predicate the predicate 288 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group 289 * @throws NullPointerException if the given group or predicate is null 290 * @throws SecurityException if the current thread cannot modify 291 * thread groups from this thread's thread group up to the system thread group 292 * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}. 293 */ 294 @Deprecated 295 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) { 296 return findThreadGroups(threadGroup, recurse, (Predicate<ThreadGroup>) predicate::test); 297 } 298 299 /** 300 * Finds all active thread groups which match the given predicate. 301 * 302 * @param predicate the predicate 303 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate 304 * @throws NullPointerException if the predicate is null 305 * @throws SecurityException 306 * if the current thread cannot access the system thread group 307 * @throws SecurityException if the current thread cannot modify 308 * thread groups from this thread's thread group up to the system thread group 309 * @deprecated Use {@link #findThreadGroups(Predicate)}. 310 */ 311 @Deprecated 312 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroupPredicate predicate) { 313 return findThreadGroups(getSystemThreadGroup(), true, predicate); 314 } 315 316 /** 317 * Finds active thread groups with the specified group name. 318 * 319 * @param threadGroupName The thread group name 320 * @return the thread groups with the specified group name or an empty collection if no such thread group exists. The collection returned is always unmodifiable. 321 * @throws NullPointerException if group name is null 322 * @throws SecurityException 323 * if the current thread cannot access the system thread group 324 * 325 * @throws SecurityException if the current thread cannot modify 326 * thread groups from this thread's thread group up to the system thread group 327 */ 328 public static Collection<ThreadGroup> findThreadGroupsByName(final String threadGroupName) { 329 return findThreadGroups(predicateThreadGroup(threadGroupName)); 330 } 331 332 /** 333 * Finds all active threads which match the given predicate. 334 * 335 * @param predicate the predicate 336 * @return An unmodifiable {@link Collection} of active threads matching the given predicate 337 * @throws NullPointerException if the predicate is null 338 * @throws SecurityException 339 * if the current thread cannot access the system thread group 340 * @throws SecurityException if the current thread cannot modify 341 * thread groups from this thread's thread group up to the system thread group 342 * @since 3.13.0 343 */ 344 public static Collection<Thread> findThreads(final Predicate<Thread> predicate) { 345 return findThreads(getSystemThreadGroup(), true, predicate); 346 } 347 348 /** 349 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). 350 * 351 * @param threadGroup the thread group 352 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group 353 * @param predicate the predicate 354 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group 355 * @throws NullPointerException if the given group or predicate is null 356 * @throws SecurityException if the current thread cannot modify 357 * thread groups from this thread's thread group up to the system thread group 358 * @since 3.13.0 359 */ 360 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate<Thread> predicate) { 361 Objects.requireNonNull(threadGroup, "The group must not be null"); 362 Objects.requireNonNull(predicate, "The predicate must not be null"); 363 int count = threadGroup.activeCount(); 364 Thread[] threads; 365 do { 366 threads = new Thread[count + count / 2 + 1]; //slightly grow the array size 367 count = threadGroup.enumerate(threads, recurse); 368 //return value of enumerate() must be strictly less than the array size according to javadoc 369 } while (count >= threads.length); 370 return Collections.unmodifiableCollection(Stream.of(threads).limit(count).filter(predicate).collect(Collectors.toList())); 371 } 372 373 /** 374 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). 375 * 376 * @param threadGroup the thread group 377 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group 378 * @param predicate the predicate 379 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group 380 * @throws NullPointerException if the given group or predicate is null 381 * @throws SecurityException if the current thread cannot modify 382 * thread groups from this thread's thread group up to the system thread group 383 * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}. 384 */ 385 @Deprecated 386 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) { 387 return findThreads(threadGroup, recurse, (Predicate<Thread>) predicate::test); 388 } 389 390 /** 391 * Finds all active threads which match the given predicate. 392 * 393 * @param predicate the predicate 394 * @return An unmodifiable {@link Collection} of active threads matching the given predicate 395 * @throws NullPointerException if the predicate is null 396 * @throws SecurityException 397 * if the current thread cannot access the system thread group 398 * @throws SecurityException if the current thread cannot modify 399 * thread groups from this thread's thread group up to the system thread group 400 * @deprecated Use {@link #findThreads(Predicate)}. 401 */ 402 @Deprecated 403 public static Collection<Thread> findThreads(final ThreadPredicate predicate) { 404 return findThreads(getSystemThreadGroup(), true, predicate); 405 } 406 407 /** 408 * Finds active threads with the specified name. 409 * 410 * @param threadName The thread name 411 * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable. 412 * @throws NullPointerException if the specified name is null 413 * @throws SecurityException 414 * if the current thread cannot access the system thread group 415 * 416 * @throws SecurityException if the current thread cannot modify 417 * thread groups from this thread's thread group up to the system thread group 418 */ 419 public static Collection<Thread> findThreadsByName(final String threadName) { 420 return findThreads(predicateThread(threadName)); 421 } 422 423 /** 424 * Finds active threads with the specified name if they belong to a thread group with the specified group name. 425 * 426 * @param threadName The thread name 427 * @param threadGroupName The thread group name 428 * @return The threads which belongs to a thread group with the specified group name and the thread's name match the specified name, 429 * An empty collection is returned if no such thread exists. The collection returned is always unmodifiable. 430 * @throws NullPointerException if the specified thread name or group name is null 431 * @throws SecurityException 432 * if the current thread cannot access the system thread group 433 * 434 * @throws SecurityException if the current thread cannot modify 435 * thread groups from this thread's thread group up to the system thread group 436 */ 437 public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) { 438 Objects.requireNonNull(threadName, "threadName"); 439 Objects.requireNonNull(threadGroupName, "threadGroupName"); 440 return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream() 441 .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList())); 442 } 443 444 /** 445 * Finds active threads with the specified name if they belong to a specified thread group. 446 * 447 * @param threadName The thread name 448 * @param threadGroup The thread group 449 * @return The threads which belongs to a thread group and the thread's name match the specified name, 450 * An empty collection is returned if no such thread exists. The collection returned is always unmodifiable. 451 * @throws NullPointerException if the specified thread name or group is null 452 * @throws SecurityException 453 * if the current thread cannot access the system thread group 454 * 455 * @throws SecurityException if the current thread cannot modify 456 * thread groups from this thread's thread group up to the system thread group 457 */ 458 public static Collection<Thread> findThreadsByName(final String threadName, final ThreadGroup threadGroup) { 459 return findThreads(threadGroup, false, predicateThread(threadName)); 460 } 461 462 /** 463 * Gets all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed). 464 * 465 * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable. 466 * @throws SecurityException 467 * if the current thread cannot access the system thread group 468 * 469 * @throws SecurityException if the current thread cannot modify 470 * thread groups from this thread's thread group up to the system thread group 471 */ 472 public static Collection<ThreadGroup> getAllThreadGroups() { 473 return findThreadGroups(Predicates.truePredicate()); 474 } 475 476 /** 477 * Gets all active threads (A thread is active if it has been started and has not yet died). 478 * 479 * @return all active threads. The collection returned is always unmodifiable. 480 * @throws SecurityException 481 * if the current thread cannot access the system thread group 482 * 483 * @throws SecurityException if the current thread cannot modify 484 * thread groups from this thread's thread group up to the system thread group 485 */ 486 public static Collection<Thread> getAllThreads() { 487 return findThreads(Predicates.truePredicate()); 488 } 489 490 /** 491 * Gets the system thread group (sometimes also referred as "root thread group"). 492 * <p> 493 * This method returns null if this thread has died (been stopped). 494 * </p> 495 * 496 * @return the system thread group 497 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the 498 * system thread group 499 */ 500 public static ThreadGroup getSystemThreadGroup() { 501 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 502 while (threadGroup != null && threadGroup.getParent() != null) { 503 threadGroup = threadGroup.getParent(); 504 } 505 return threadGroup; 506 } 507 508 /** 509 * Waits for the given thread to die for the given duration. Implemented using {@link Thread#join(long, int)}. 510 * 511 * @param thread The thread to join. 512 * @param duration How long to wait. 513 * @throws InterruptedException if any thread has interrupted the current thread. 514 * @see Thread#join(long, int) 515 * @since 3.12.0 516 */ 517 public static void join(final Thread thread, final Duration duration) throws InterruptedException { 518 DurationUtils.accept(thread::join, duration); 519 } 520 521 private static <T> Predicate<T> namePredicate(final String name, final Function<T, String> nameGetter) { 522 return (Predicate<T>) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name)); 523 } 524 525 private static Predicate<Thread> predicateThread(final String threadName) { 526 return namePredicate(threadName, Thread::getName); 527 } 528 529 private static Predicate<ThreadGroup> predicateThreadGroup(final String threadGroupName) { 530 return namePredicate(threadGroupName, ThreadGroup::getName); 531 } 532 533 /** 534 * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}. 535 * 536 * @param duration How long to sleep. 537 * @throws InterruptedException if any thread has interrupted the current thread. 538 * @see Thread#sleep(long, int) 539 * @since 3.12.0 540 */ 541 public static void sleep(final Duration duration) throws InterruptedException { 542 DurationUtils.accept(Thread::sleep, duration); 543 } 544 545 /** 546 * Sleeps for the given duration while ignoring {@link InterruptedException}. 547 * <p> 548 * The sleep duration may be shorter than duration if we catch a {@link InterruptedException}. 549 * </p> 550 * 551 * @param duration the length of time to sleep. 552 * @since 3.13.0 553 */ 554 public static void sleepQuietly(final Duration duration) { 555 try { 556 sleep(duration); 557 } catch (final InterruptedException ignore) { 558 // Ignore & be quiet. 559 } 560 } 561 562 /** 563 * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ThreadUtils.getAllThreads()} 564 * <p> 565 * This constructor is public to permit tools that require a JavaBean instance to operate. 566 * </p> 567 * 568 * @deprecated TODO Make private in 4.0. 569 */ 570 @Deprecated 571 public ThreadUtils() { 572 // empty 573 } 574}