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 if the current thread cannot access the system thread group. 181 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 182 */ 183 public static Thread findThreadById(final long threadId) { 184 if (threadId <= 0) { 185 throw new IllegalArgumentException("The thread id must be greater than zero"); 186 } 187 final Collection<Thread> result = findThreads((Predicate<Thread>) t -> t != null && t.getId() == threadId); 188 return result.isEmpty() ? null : result.iterator().next(); 189 } 190 191 /** 192 * Finds the active thread with the specified id if it belongs to a thread group with the specified group name. 193 * 194 * @param threadId The thread id. 195 * @param threadGroupName The thread group name. 196 * @return The threads which belongs to a thread group with the specified group name and the thread's id match the specified id. {@code null} is returned if 197 * no such thread exists. 198 * @throws NullPointerException if the group name is null. 199 * @throws IllegalArgumentException if the specified id is zero or negative. 200 * @throws SecurityException if the current thread cannot access the system thread group. 201 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 202 */ 203 public static Thread findThreadById(final long threadId, final String threadGroupName) { 204 Objects.requireNonNull(threadGroupName, "threadGroupName"); 205 final Thread thread = findThreadById(threadId); 206 if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) { 207 return thread; 208 } 209 return null; 210 } 211 212 /** 213 * Finds the active thread with the specified id if it belongs to the specified thread group. 214 * 215 * @param threadId The thread id. 216 * @param threadGroup The thread group. 217 * @return The thread which belongs to a specified thread group and the thread's id match the specified id. {@code null} is returned if no such thread 218 * exists. 219 * @throws NullPointerException if {@code threadGroup == null}. 220 * @throws IllegalArgumentException if the specified id is zero or negative. 221 * @throws SecurityException if the current thread cannot access the system thread group. 222 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 223 */ 224 public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { 225 Objects.requireNonNull(threadGroup, "threadGroup"); 226 final Thread thread = findThreadById(threadId); 227 if (thread != null && threadGroup.equals(thread.getThreadGroup())) { 228 return thread; 229 } 230 return null; 231 } 232 233 /** 234 * Finds all active thread groups which match the given predicate. 235 * 236 * @param predicate the predicate. 237 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate. 238 * @throws NullPointerException if the predicate is null. 239 * @throws SecurityException if the current thread cannot access the system thread group. 240 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 241 * @since 3.13.0 242 */ 243 public static Collection<ThreadGroup> findThreadGroups(final Predicate<ThreadGroup> predicate) { 244 return findThreadGroups(getSystemThreadGroup(), true, predicate); 245 } 246 247 /** 248 * 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). 249 * 250 * @param threadGroup the thread group. 251 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group. 252 * @param predicate the predicate. 253 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group. 254 * @throws NullPointerException if the given group or predicate is null. 255 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 256 * @since 3.13.0 257 */ 258 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate<ThreadGroup> predicate) { 259 Objects.requireNonNull(threadGroup, "threadGroup"); 260 Objects.requireNonNull(predicate, "predicate"); 261 int count = threadGroup.activeGroupCount(); 262 ThreadGroup[] threadGroups; 263 do { 264 threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size 265 count = threadGroup.enumerate(threadGroups, recurse); 266 //return value of enumerate() must be strictly less than the array size according to Javadoc 267 } while (count >= threadGroups.length); 268 return Collections.unmodifiableCollection(Stream.of(threadGroups).limit(count).filter(predicate).collect(Collectors.toList())); 269 } 270 271 /** 272 * 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). 273 * 274 * @param threadGroup the thread group. 275 * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group. 276 * @param predicate the predicate. 277 * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group. 278 * @throws NullPointerException if the given group or predicate is null. 279 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 280 * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}. 281 */ 282 @Deprecated 283 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) { 284 return findThreadGroups(threadGroup, recurse, (Predicate<ThreadGroup>) predicate::test); 285 } 286 287 /** 288 * Finds all active thread groups which match the given predicate. 289 * 290 * @param predicate the predicate. 291 * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate. 292 * @throws NullPointerException if the predicate is null. 293 * @throws SecurityException if the current thread cannot access the system thread group. 294 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 295 * @deprecated Use {@link #findThreadGroups(Predicate)}. 296 */ 297 @Deprecated 298 public static Collection<ThreadGroup> findThreadGroups(final ThreadGroupPredicate predicate) { 299 return findThreadGroups(getSystemThreadGroup(), true, predicate); 300 } 301 302 /** 303 * Finds active thread groups with the specified group name. 304 * 305 * @param threadGroupName The thread group name. 306 * @return the thread groups with the specified group name or an empty collection if no such thread group exists. The collection returned is always 307 * unmodifiable. 308 * @throws NullPointerException if group name is null. 309 * @throws SecurityException if the current thread cannot access the system thread group. 310 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 311 */ 312 public static Collection<ThreadGroup> findThreadGroupsByName(final String threadGroupName) { 313 return findThreadGroups(predicateThreadGroup(threadGroupName)); 314 } 315 316 /** 317 * Finds all active threads which match the given predicate. 318 * 319 * @param predicate the predicate. 320 * @return An unmodifiable {@link Collection} of active threads matching the given predicate. 321 * @throws NullPointerException if the predicate is null. 322 * @throws SecurityException if the current thread cannot access the system thread group. 323 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 324 * @since 3.13.0 325 */ 326 public static Collection<Thread> findThreads(final Predicate<Thread> predicate) { 327 return findThreads(getSystemThreadGroup(), true, predicate); 328 } 329 330 /** 331 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). 332 * 333 * @param threadGroup the thread group. 334 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group. 335 * @param predicate the predicate. 336 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group. 337 * @throws NullPointerException if the given group or predicate is null. 338 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 339 * @since 3.13.0 340 */ 341 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate<Thread> predicate) { 342 Objects.requireNonNull(threadGroup, "The group must not be null"); 343 Objects.requireNonNull(predicate, "The predicate must not be null"); 344 int count = threadGroup.activeCount(); 345 Thread[] threads; 346 do { 347 threads = new Thread[count + count / 2 + 1]; //slightly grow the array size 348 count = threadGroup.enumerate(threads, recurse); 349 //return value of enumerate() must be strictly less than the array size according to javadoc 350 } while (count >= threads.length); 351 return Collections.unmodifiableCollection(Stream.of(threads).limit(count).filter(predicate).collect(Collectors.toList())); 352 } 353 354 /** 355 * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). 356 * 357 * @param threadGroup the thread group. 358 * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group. 359 * @param predicate the predicate. 360 * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group. 361 * @throws NullPointerException if the given group or predicate is null. 362 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 363 * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}. 364 */ 365 @Deprecated 366 public static Collection<Thread> findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) { 367 return findThreads(threadGroup, recurse, (Predicate<Thread>) predicate::test); 368 } 369 370 /** 371 * Finds all active threads which match the given predicate. 372 * 373 * @param predicate the predicate. 374 * @return An unmodifiable {@link Collection} of active threads matching the given predicate. 375 * @throws NullPointerException if the predicate is null. 376 * @throws SecurityException if the current thread cannot access the system thread group. 377 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 378 * @deprecated Use {@link #findThreads(Predicate)}. 379 */ 380 @Deprecated 381 public static Collection<Thread> findThreads(final ThreadPredicate predicate) { 382 return findThreads(getSystemThreadGroup(), true, predicate); 383 } 384 385 /** 386 * Finds active threads with the specified name. 387 * 388 * @param threadName The thread name. 389 * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable. 390 * @throws NullPointerException if the specified name is null. 391 * @throws SecurityException if the current thread cannot access the system thread group. 392 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 393 */ 394 public static Collection<Thread> findThreadsByName(final String threadName) { 395 return findThreads(predicateThread(threadName)); 396 } 397 398 /** 399 * Finds active threads with the specified name if they belong to a thread group with the specified group name. 400 * 401 * @param threadName The thread name. 402 * @param threadGroupName The thread group name. 403 * @return The threads which belongs to a thread group with the specified group name and the thread's name match the specified name, An empty collection is 404 * returned if no such thread exists. The collection returned is always unmodifiable. 405 * @throws NullPointerException if the specified thread name or group name is null. 406 * @throws SecurityException if the current thread cannot access the system thread group. 407 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 408 */ 409 public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) { 410 Objects.requireNonNull(threadName, "threadName"); 411 Objects.requireNonNull(threadGroupName, "threadGroupName"); 412 return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream() 413 .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList())); 414 } 415 416 /** 417 * Finds active threads with the specified name if they belong to a specified thread group. 418 * 419 * @param threadName The thread name. 420 * @param threadGroup The thread group. 421 * @return The threads which belongs to a thread group and the thread's name match the specified name, An empty collection is returned if no such thread 422 * exists. The collection returned is always unmodifiable. 423 * @throws NullPointerException if the specified thread name or group is null. 424 * @throws SecurityException if the current thread cannot access the system thread group. 425 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 426 */ 427 public static Collection<Thread> findThreadsByName(final String threadName, final ThreadGroup threadGroup) { 428 return findThreads(threadGroup, false, predicateThread(threadName)); 429 } 430 431 /** 432 * Gets all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed). 433 * 434 * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable. 435 * @throws SecurityException if the current thread cannot access the system thread group. 436 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 437 */ 438 public static Collection<ThreadGroup> getAllThreadGroups() { 439 return findThreadGroups(Predicates.truePredicate()); 440 } 441 442 /** 443 * Gets all active threads (A thread is active if it has been started and has not yet died). 444 * 445 * @return all active threads. The collection returned is always unmodifiable. 446 * @throws SecurityException if the current thread cannot access the system thread group. 447 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 448 */ 449 public static Collection<Thread> getAllThreads() { 450 return findThreads(Predicates.truePredicate()); 451 } 452 453 /** 454 * Gets the system thread group (sometimes also referred as "root thread group"). 455 * <p> 456 * This method returns null if this thread has died (been stopped). 457 * </p> 458 * 459 * @return the system thread group. 460 * @throws SecurityException if the current thread cannot modify thread groups from this thread's thread group up to the system thread group. 461 */ 462 public static ThreadGroup getSystemThreadGroup() { 463 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 464 while (threadGroup != null && threadGroup.getParent() != null) { 465 threadGroup = threadGroup.getParent(); 466 } 467 return threadGroup; 468 } 469 470 /** 471 * Waits for the given thread to die for the given duration. Implemented using {@link Thread#join(long, int)}. 472 * 473 * @param thread The thread to join. 474 * @param duration How long to wait. 475 * @throws InterruptedException if any thread has interrupted the current thread. 476 * @see Thread#join(long, int) 477 * @since 3.12.0 478 */ 479 public static void join(final Thread thread, final Duration duration) throws InterruptedException { 480 DurationUtils.accept(thread::join, duration); 481 } 482 483 private static <T> Predicate<T> namePredicate(final String name, final Function<T, String> nameGetter) { 484 return (Predicate<T>) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name)); 485 } 486 487 private static Predicate<Thread> predicateThread(final String threadName) { 488 return namePredicate(threadName, Thread::getName); 489 } 490 491 private static Predicate<ThreadGroup> predicateThreadGroup(final String threadGroupName) { 492 return namePredicate(threadGroupName, ThreadGroup::getName); 493 } 494 495 /** 496 * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}. 497 * 498 * @param duration How long to sleep. 499 * @throws InterruptedException if any thread has interrupted the current thread. 500 * @see Thread#sleep(long, int) 501 * @since 3.12.0 502 */ 503 public static void sleep(final Duration duration) throws InterruptedException { 504 DurationUtils.accept(Thread::sleep, duration); 505 } 506 507 /** 508 * Sleeps for the given duration while ignoring {@link InterruptedException}. 509 * <p> 510 * The sleep duration may be shorter than duration if we catch a {@link InterruptedException}. 511 * </p> 512 * 513 * @param duration the length of time to sleep. 514 * @since 3.13.0 515 */ 516 public static void sleepQuietly(final Duration duration) { 517 try { 518 sleep(duration); 519 } catch (final InterruptedException ignore) { 520 // Ignore & be quiet. 521 } 522 } 523 524 /** 525 * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ThreadUtils.getAllThreads()} 526 * <p> 527 * This constructor is public to permit tools that require a JavaBean instance to operate. 528 * </p> 529 * 530 * @deprecated TODO Make private in 4.0. 531 */ 532 @Deprecated 533 public ThreadUtils() { 534 // empty 535 } 536}