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