1 /* 2 * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.io.PrintStream; 29 import java.util.Arrays; 30 31 /** 32 * A thread group represents a set of threads. In addition, a thread 33 * group can also include other thread groups. The thread groups form 34 * a tree in which every thread group except the initial thread group 35 * has a parent. 36 * <p> 37 * A thread is allowed to access information about its own thread 38 * group, but not to access information about its thread group's 39 * parent thread group or any other thread groups. 40 * 41 * @author unascribed 42 * @since 1.0 43 */ 44 /* The locking strategy for this code is to try to lock only one level of the 45 * tree wherever possible, but otherwise to lock from the bottom up. 46 * That is, from child thread groups to parents. 47 * This has the advantage of limiting the number of locks that need to be held 48 * and in particular avoids having to grab the lock for the root thread group, 49 * (or a global lock) which would be a source of contention on a 50 * multi-processor system with many thread groups. 51 * This policy often leads to taking a snapshot of the state of a thread group 52 * and working off of that snapshot, rather than holding the thread group locked 53 * while we work on the children. 54 */ 55 public 56 class ThreadGroup implements Thread.UncaughtExceptionHandler { 57 private final ThreadGroup parent; 58 String name; 59 int maxPriority; 60 boolean destroyed; 61 boolean daemon; 62 63 int nUnstartedThreads = 0; 64 int nthreads; 65 Thread threads[]; 66 67 int ngroups; 68 ThreadGroup groups[]; 69 70 /** 71 * Creates an empty Thread group that is not in any Thread group. 72 * This method is used to create the system Thread group. 73 */ ThreadGroup()74 private ThreadGroup() { // called from C code 75 this.name = "system"; 76 this.maxPriority = Thread.MAX_PRIORITY; 77 this.parent = null; 78 } 79 80 /** 81 * Constructs a new thread group. The parent of this new group is 82 * the thread group of the currently running thread. 83 * <p> 84 * The {@code checkAccess} method of the parent thread group is 85 * called with no arguments; this may result in a security exception. 86 * 87 * @param name the name of the new thread group. 88 * @throws SecurityException if the current thread cannot create a 89 * thread in the specified thread group. 90 * @see java.lang.ThreadGroup#checkAccess() 91 * @since 1.0 92 */ ThreadGroup(String name)93 public ThreadGroup(String name) { 94 this(Thread.currentThread().getThreadGroup(), name); 95 } 96 97 /** 98 * Creates a new thread group. The parent of this new group is the 99 * specified thread group. 100 * <p> 101 * The {@code checkAccess} method of the parent thread group is 102 * called with no arguments; this may result in a security exception. 103 * 104 * @param parent the parent thread group. 105 * @param name the name of the new thread group. 106 * @throws NullPointerException if the thread group argument is 107 * {@code null}. 108 * @throws SecurityException if the current thread cannot create a 109 * thread in the specified thread group. 110 * @see java.lang.SecurityException 111 * @see java.lang.ThreadGroup#checkAccess() 112 * @since 1.0 113 */ ThreadGroup(ThreadGroup parent, String name)114 public ThreadGroup(ThreadGroup parent, String name) { 115 this(checkParentAccess(parent), parent, name); 116 } 117 ThreadGroup(Void unused, ThreadGroup parent, String name)118 private ThreadGroup(Void unused, ThreadGroup parent, String name) { 119 this.name = name; 120 this.maxPriority = parent.maxPriority; 121 this.daemon = parent.daemon; 122 this.parent = parent; 123 parent.add(this); 124 } 125 126 /* 127 * @throws NullPointerException if the parent argument is {@code null} 128 * @throws SecurityException if the current thread cannot create a 129 * thread in the specified thread group. 130 */ checkParentAccess(ThreadGroup parent)131 private static Void checkParentAccess(ThreadGroup parent) { 132 parent.checkAccess(); 133 return null; 134 } 135 136 /** 137 * Returns the name of this thread group. 138 * 139 * @return the name of this thread group. 140 * @since 1.0 141 */ getName()142 public final String getName() { 143 return name; 144 } 145 146 /** 147 * Returns the parent of this thread group. 148 * <p> 149 * First, if the parent is not {@code null}, the 150 * {@code checkAccess} method of the parent thread group is 151 * called with no arguments; this may result in a security exception. 152 * 153 * @return the parent of this thread group. The top-level thread group 154 * is the only thread group whose parent is {@code null}. 155 * @throws SecurityException if the current thread cannot modify 156 * this thread group. 157 * @see java.lang.ThreadGroup#checkAccess() 158 * @see java.lang.SecurityException 159 * @see java.lang.RuntimePermission 160 * @since 1.0 161 */ getParent()162 public final ThreadGroup getParent() { 163 if (parent != null) 164 parent.checkAccess(); 165 return parent; 166 } 167 168 /** 169 * Returns the maximum priority of this thread group. Threads that are 170 * part of this group cannot have a higher priority than the maximum 171 * priority. 172 * 173 * @return the maximum priority that a thread in this thread group 174 * can have. 175 * @see #setMaxPriority 176 * @since 1.0 177 */ getMaxPriority()178 public final int getMaxPriority() { 179 return maxPriority; 180 } 181 182 /** 183 * Tests if this thread group is a daemon thread group. A 184 * daemon thread group is automatically destroyed when its last 185 * thread is stopped or its last thread group is destroyed. 186 * 187 * @return {@code true} if this thread group is a daemon thread group; 188 * {@code false} otherwise. 189 * @since 1.0 190 */ isDaemon()191 public final boolean isDaemon() { 192 return daemon; 193 } 194 195 /** 196 * Tests if this thread group has been destroyed. 197 * 198 * @return true if this object is destroyed 199 * @since 1.1 200 */ isDestroyed()201 public synchronized boolean isDestroyed() { 202 return destroyed; 203 } 204 205 /** 206 * Changes the daemon status of this thread group. 207 * <p> 208 * First, the {@code checkAccess} method of this thread group is 209 * called with no arguments; this may result in a security exception. 210 * <p> 211 * A daemon thread group is automatically destroyed when its last 212 * thread is stopped or its last thread group is destroyed. 213 * 214 * @param daemon if {@code true}, marks this thread group as 215 * a daemon thread group; otherwise, marks this 216 * thread group as normal. 217 * @throws SecurityException if the current thread cannot modify 218 * this thread group. 219 * @see java.lang.SecurityException 220 * @see java.lang.ThreadGroup#checkAccess() 221 * @since 1.0 222 */ setDaemon(boolean daemon)223 public final void setDaemon(boolean daemon) { 224 checkAccess(); 225 this.daemon = daemon; 226 } 227 228 /** 229 * Sets the maximum priority of the group. Threads in the thread 230 * group that already have a higher priority are not affected. 231 * <p> 232 * First, the {@code checkAccess} method of this thread group is 233 * called with no arguments; this may result in a security exception. 234 * <p> 235 * If the {@code pri} argument is less than 236 * {@link Thread#MIN_PRIORITY} or greater than 237 * {@link Thread#MAX_PRIORITY}, the maximum priority of the group 238 * remains unchanged. 239 * <p> 240 * Otherwise, the priority of this ThreadGroup object is set to the 241 * smaller of the specified {@code pri} and the maximum permitted 242 * priority of the parent of this thread group. (If this thread group 243 * is the system thread group, which has no parent, then its maximum 244 * priority is simply set to {@code pri}.) Then this method is 245 * called recursively, with {@code pri} as its argument, for 246 * every thread group that belongs to this thread group. 247 * 248 * @param pri the new priority of the thread group. 249 * @throws SecurityException if the current thread cannot modify 250 * this thread group. 251 * @see #getMaxPriority 252 * @see java.lang.SecurityException 253 * @see java.lang.ThreadGroup#checkAccess() 254 * @since 1.0 255 */ setMaxPriority(int pri)256 public final void setMaxPriority(int pri) { 257 int ngroupsSnapshot; 258 ThreadGroup[] groupsSnapshot; 259 synchronized (this) { 260 checkAccess(); 261 if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) { 262 return; 263 } 264 maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri; 265 ngroupsSnapshot = ngroups; 266 if (groups != null) { 267 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 268 } else { 269 groupsSnapshot = null; 270 } 271 } 272 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 273 groupsSnapshot[i].setMaxPriority(pri); 274 } 275 } 276 277 /** 278 * Tests if this thread group is either the thread group 279 * argument or one of its ancestor thread groups. 280 * 281 * @param g a thread group. 282 * @return {@code true} if this thread group is the thread group 283 * argument or one of its ancestor thread groups; 284 * {@code false} otherwise. 285 * @since 1.0 286 */ parentOf(ThreadGroup g)287 public final boolean parentOf(ThreadGroup g) { 288 for (; g != null ; g = g.parent) { 289 if (g == this) { 290 return true; 291 } 292 } 293 return false; 294 } 295 296 /** 297 * Determines if the currently running thread has permission to 298 * modify this thread group. 299 * <p> 300 * If there is a security manager, its {@code checkAccess} method 301 * is called with this thread group as its argument. This may result 302 * in throwing a {@code SecurityException}. 303 * 304 * @throws SecurityException if the current thread is not allowed to 305 * access this thread group. 306 * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup) 307 * @since 1.0 308 */ checkAccess()309 public final void checkAccess() { 310 SecurityManager security = System.getSecurityManager(); 311 if (security != null) { 312 security.checkAccess(this); 313 } 314 } 315 316 /** 317 * Returns an estimate of the number of active threads in this thread 318 * group and its subgroups. Recursively iterates over all subgroups in 319 * this thread group. 320 * 321 * <p> The value returned is only an estimate because the number of 322 * threads may change dynamically while this method traverses internal 323 * data structures, and might be affected by the presence of certain 324 * system threads. This method is intended primarily for debugging 325 * and monitoring purposes. 326 * 327 * @return an estimate of the number of active threads in this thread 328 * group and in any other thread group that has this thread 329 * group as an ancestor 330 * 331 * @since 1.0 332 */ activeCount()333 public int activeCount() { 334 int result; 335 // Snapshot sub-group data so we don't hold this lock 336 // while our children are computing. 337 int ngroupsSnapshot; 338 ThreadGroup[] groupsSnapshot; 339 synchronized (this) { 340 if (destroyed) { 341 return 0; 342 } 343 result = nthreads; 344 ngroupsSnapshot = ngroups; 345 if (groups != null) { 346 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 347 } else { 348 groupsSnapshot = null; 349 } 350 } 351 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 352 result += groupsSnapshot[i].activeCount(); 353 } 354 return result; 355 } 356 357 /** 358 * Copies into the specified array every active thread in this 359 * thread group and its subgroups. 360 * 361 * <p> An invocation of this method behaves in exactly the same 362 * way as the invocation 363 * 364 * <blockquote> 365 * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)} 366 * </blockquote> 367 * 368 * @param list 369 * an array into which to put the list of threads 370 * 371 * @return the number of threads put into the array 372 * 373 * @throws SecurityException 374 * if {@linkplain #checkAccess checkAccess} determines that 375 * the current thread cannot access this thread group 376 * 377 * @since 1.0 378 */ enumerate(Thread list[])379 public int enumerate(Thread list[]) { 380 checkAccess(); 381 return enumerate(list, 0, true); 382 } 383 384 /** 385 * Copies into the specified array every active thread in this 386 * thread group. If {@code recurse} is {@code true}, 387 * this method recursively enumerates all subgroups of this 388 * thread group and references to every active thread in these 389 * subgroups are also included. If the array is too short to 390 * hold all the threads, the extra threads are silently ignored. 391 * 392 * <p> An application might use the {@linkplain #activeCount activeCount} 393 * method to get an estimate of how big the array should be, however 394 * <i>if the array is too short to hold all the threads, the extra threads 395 * are silently ignored.</i> If it is critical to obtain every active 396 * thread in this thread group, the caller should verify that the returned 397 * int value is strictly less than the length of {@code list}. 398 * 399 * <p> Due to the inherent race condition in this method, it is recommended 400 * that the method only be used for debugging and monitoring purposes. 401 * 402 * @param list 403 * an array into which to put the list of threads 404 * 405 * @param recurse 406 * if {@code true}, recursively enumerate all subgroups of this 407 * thread group 408 * 409 * @return the number of threads put into the array 410 * 411 * @throws SecurityException 412 * if {@linkplain #checkAccess checkAccess} determines that 413 * the current thread cannot access this thread group 414 * 415 * @since 1.0 416 */ enumerate(Thread list[], boolean recurse)417 public int enumerate(Thread list[], boolean recurse) { 418 checkAccess(); 419 return enumerate(list, 0, recurse); 420 } 421 enumerate(Thread list[], int n, boolean recurse)422 private int enumerate(Thread list[], int n, boolean recurse) { 423 int ngroupsSnapshot = 0; 424 ThreadGroup[] groupsSnapshot = null; 425 synchronized (this) { 426 if (destroyed) { 427 return n; 428 } 429 int nt = nthreads; 430 if (nt > list.length - n) { 431 nt = list.length - n; 432 } 433 for (int i = 0; i < nt; i++) { 434 if (threads[i].isAlive()) { 435 list[n++] = threads[i]; 436 } 437 } 438 if (recurse) { 439 ngroupsSnapshot = ngroups; 440 if (groups != null) { 441 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 442 } else { 443 groupsSnapshot = null; 444 } 445 } 446 } 447 if (recurse) { 448 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 449 n = groupsSnapshot[i].enumerate(list, n, true); 450 } 451 } 452 return n; 453 } 454 455 /** 456 * Returns an estimate of the number of active groups in this 457 * thread group and its subgroups. Recursively iterates over 458 * all subgroups in this thread group. 459 * 460 * <p> The value returned is only an estimate because the number of 461 * thread groups may change dynamically while this method traverses 462 * internal data structures. This method is intended primarily for 463 * debugging and monitoring purposes. 464 * 465 * @return the number of active thread groups with this thread group as 466 * an ancestor 467 * 468 * @since 1.0 469 */ activeGroupCount()470 public int activeGroupCount() { 471 int ngroupsSnapshot; 472 ThreadGroup[] groupsSnapshot; 473 synchronized (this) { 474 if (destroyed) { 475 return 0; 476 } 477 ngroupsSnapshot = ngroups; 478 if (groups != null) { 479 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 480 } else { 481 groupsSnapshot = null; 482 } 483 } 484 int n = ngroupsSnapshot; 485 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 486 n += groupsSnapshot[i].activeGroupCount(); 487 } 488 return n; 489 } 490 491 /** 492 * Copies into the specified array references to every active 493 * subgroup in this thread group and its subgroups. 494 * 495 * <p> An invocation of this method behaves in exactly the same 496 * way as the invocation 497 * 498 * <blockquote> 499 * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)} 500 * </blockquote> 501 * 502 * @param list 503 * an array into which to put the list of thread groups 504 * 505 * @return the number of thread groups put into the array 506 * 507 * @throws SecurityException 508 * if {@linkplain #checkAccess checkAccess} determines that 509 * the current thread cannot access this thread group 510 * 511 * @since 1.0 512 */ enumerate(ThreadGroup list[])513 public int enumerate(ThreadGroup list[]) { 514 checkAccess(); 515 return enumerate(list, 0, true); 516 } 517 518 /** 519 * Copies into the specified array references to every active 520 * subgroup in this thread group. If {@code recurse} is 521 * {@code true}, this method recursively enumerates all subgroups of this 522 * thread group and references to every active thread group in these 523 * subgroups are also included. 524 * 525 * <p> An application might use the 526 * {@linkplain #activeGroupCount activeGroupCount} method to 527 * get an estimate of how big the array should be, however <i>if the 528 * array is too short to hold all the thread groups, the extra thread 529 * groups are silently ignored.</i> If it is critical to obtain every 530 * active subgroup in this thread group, the caller should verify that 531 * the returned int value is strictly less than the length of 532 * {@code list}. 533 * 534 * <p> Due to the inherent race condition in this method, it is recommended 535 * that the method only be used for debugging and monitoring purposes. 536 * 537 * @param list 538 * an array into which to put the list of thread groups 539 * 540 * @param recurse 541 * if {@code true}, recursively enumerate all subgroups 542 * 543 * @return the number of thread groups put into the array 544 * 545 * @throws SecurityException 546 * if {@linkplain #checkAccess checkAccess} determines that 547 * the current thread cannot access this thread group 548 * 549 * @since 1.0 550 */ enumerate(ThreadGroup list[], boolean recurse)551 public int enumerate(ThreadGroup list[], boolean recurse) { 552 checkAccess(); 553 return enumerate(list, 0, recurse); 554 } 555 enumerate(ThreadGroup list[], int n, boolean recurse)556 private int enumerate(ThreadGroup list[], int n, boolean recurse) { 557 int ngroupsSnapshot = 0; 558 ThreadGroup[] groupsSnapshot = null; 559 synchronized (this) { 560 if (destroyed) { 561 return n; 562 } 563 int ng = ngroups; 564 if (ng > list.length - n) { 565 ng = list.length - n; 566 } 567 if (ng > 0) { 568 System.arraycopy(groups, 0, list, n, ng); 569 n += ng; 570 } 571 if (recurse) { 572 ngroupsSnapshot = ngroups; 573 if (groups != null) { 574 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 575 } else { 576 groupsSnapshot = null; 577 } 578 } 579 } 580 if (recurse) { 581 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 582 n = groupsSnapshot[i].enumerate(list, n, true); 583 } 584 } 585 return n; 586 } 587 588 /** 589 * Stops all threads in this thread group. 590 * <p> 591 * First, the {@code checkAccess} method of this thread group is 592 * called with no arguments; this may result in a security exception. 593 * <p> 594 * This method then calls the {@code stop} method on all the 595 * threads in this thread group and in all of its subgroups. 596 * 597 * @throws SecurityException if the current thread is not allowed 598 * to access this thread group or any of the threads in 599 * the thread group. 600 * @see java.lang.SecurityException 601 * @see java.lang.Thread#stop() 602 * @see java.lang.ThreadGroup#checkAccess() 603 * @since 1.0 604 * @deprecated This method is inherently unsafe. See 605 * {@link Thread#stop} for details. 606 */ 607 @Deprecated(since="1.2") stop()608 public final void stop() { 609 if (stopOrSuspend(false)) 610 Thread.currentThread().stop(); 611 } 612 613 /** 614 * Interrupts all threads in this thread group. 615 * <p> 616 * First, the {@code checkAccess} method of this thread group is 617 * called with no arguments; this may result in a security exception. 618 * <p> 619 * This method then calls the {@code interrupt} method on all the 620 * threads in this thread group and in all of its subgroups. 621 * 622 * @throws SecurityException if the current thread is not allowed 623 * to access this thread group or any of the threads in 624 * the thread group. 625 * @see java.lang.Thread#interrupt() 626 * @see java.lang.SecurityException 627 * @see java.lang.ThreadGroup#checkAccess() 628 * @since 1.2 629 */ interrupt()630 public final void interrupt() { 631 int ngroupsSnapshot; 632 ThreadGroup[] groupsSnapshot; 633 synchronized (this) { 634 checkAccess(); 635 for (int i = 0 ; i < nthreads ; i++) { 636 threads[i].interrupt(); 637 } 638 ngroupsSnapshot = ngroups; 639 if (groups != null) { 640 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 641 } else { 642 groupsSnapshot = null; 643 } 644 } 645 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 646 groupsSnapshot[i].interrupt(); 647 } 648 } 649 650 /** 651 * Suspends all threads in this thread group. 652 * <p> 653 * First, the {@code checkAccess} method of this thread group is 654 * called with no arguments; this may result in a security exception. 655 * <p> 656 * This method then calls the {@code suspend} method on all the 657 * threads in this thread group and in all of its subgroups. 658 * 659 * @throws SecurityException if the current thread is not allowed 660 * to access this thread group or any of the threads in 661 * the thread group. 662 * @see java.lang.Thread#suspend() 663 * @see java.lang.SecurityException 664 * @see java.lang.ThreadGroup#checkAccess() 665 * @since 1.0 666 * @deprecated This method is inherently deadlock-prone. See 667 * {@link Thread#suspend} for details. 668 */ 669 @Deprecated(since="1.2") 670 @SuppressWarnings("deprecation") suspend()671 public final void suspend() { 672 if (stopOrSuspend(true)) 673 Thread.currentThread().suspend(); 674 } 675 676 /** 677 * Helper method: recursively stops or suspends (as directed by the 678 * boolean argument) all of the threads in this thread group and its 679 * subgroups, except the current thread. This method returns true 680 * if (and only if) the current thread is found to be in this thread 681 * group or one of its subgroups. 682 */ 683 @SuppressWarnings("deprecation") stopOrSuspend(boolean suspend)684 private boolean stopOrSuspend(boolean suspend) { 685 boolean suicide = false; 686 Thread us = Thread.currentThread(); 687 int ngroupsSnapshot; 688 ThreadGroup[] groupsSnapshot = null; 689 synchronized (this) { 690 checkAccess(); 691 for (int i = 0 ; i < nthreads ; i++) { 692 if (threads[i]==us) 693 suicide = true; 694 else if (suspend) 695 threads[i].suspend(); 696 else 697 threads[i].stop(); 698 } 699 700 ngroupsSnapshot = ngroups; 701 if (groups != null) { 702 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 703 } 704 } 705 for (int i = 0 ; i < ngroupsSnapshot ; i++) 706 suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide; 707 708 return suicide; 709 } 710 711 /** 712 * Resumes all threads in this thread group. 713 * <p> 714 * First, the {@code checkAccess} method of this thread group is 715 * called with no arguments; this may result in a security exception. 716 * <p> 717 * This method then calls the {@code resume} method on all the 718 * threads in this thread group and in all of its sub groups. 719 * 720 * @throws SecurityException if the current thread is not allowed to 721 * access this thread group or any of the threads in the 722 * thread group. 723 * @see java.lang.SecurityException 724 * @see java.lang.Thread#resume() 725 * @see java.lang.ThreadGroup#checkAccess() 726 * @since 1.0 727 * @deprecated This method is used solely in conjunction with 728 * {@code Thread.suspend} and {@code ThreadGroup.suspend}, 729 * both of which have been deprecated, as they are inherently 730 * deadlock-prone. See {@link Thread#suspend} for details. 731 */ 732 @Deprecated(since="1.2") 733 @SuppressWarnings("deprecation") resume()734 public final void resume() { 735 int ngroupsSnapshot; 736 ThreadGroup[] groupsSnapshot; 737 synchronized (this) { 738 checkAccess(); 739 for (int i = 0 ; i < nthreads ; i++) { 740 threads[i].resume(); 741 } 742 ngroupsSnapshot = ngroups; 743 if (groups != null) { 744 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 745 } else { 746 groupsSnapshot = null; 747 } 748 } 749 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 750 groupsSnapshot[i].resume(); 751 } 752 } 753 754 /** 755 * Destroys this thread group and all of its subgroups. This thread 756 * group must be empty, indicating that all threads that had been in 757 * this thread group have since stopped. 758 * <p> 759 * First, the {@code checkAccess} method of this thread group is 760 * called with no arguments; this may result in a security exception. 761 * 762 * @throws IllegalThreadStateException if the thread group is not 763 * empty or if the thread group has already been destroyed. 764 * @throws SecurityException if the current thread cannot modify this 765 * thread group. 766 * @see java.lang.ThreadGroup#checkAccess() 767 * @since 1.0 768 */ destroy()769 public final void destroy() { 770 int ngroupsSnapshot; 771 ThreadGroup[] groupsSnapshot; 772 synchronized (this) { 773 checkAccess(); 774 if (destroyed || (nthreads > 0)) { 775 throw new IllegalThreadStateException(); 776 } 777 ngroupsSnapshot = ngroups; 778 if (groups != null) { 779 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 780 } else { 781 groupsSnapshot = null; 782 } 783 if (parent != null) { 784 destroyed = true; 785 ngroups = 0; 786 groups = null; 787 nthreads = 0; 788 threads = null; 789 } 790 } 791 for (int i = 0 ; i < ngroupsSnapshot ; i += 1) { 792 groupsSnapshot[i].destroy(); 793 } 794 if (parent != null) { 795 parent.remove(this); 796 } 797 } 798 799 /** 800 * Adds the specified Thread group to this group. 801 * @param g the specified Thread group to be added 802 * @throws IllegalThreadStateException If the Thread group has been destroyed. 803 */ add(ThreadGroup g)804 private final void add(ThreadGroup g){ 805 synchronized (this) { 806 if (destroyed) { 807 throw new IllegalThreadStateException(); 808 } 809 if (groups == null) { 810 groups = new ThreadGroup[4]; 811 } else if (ngroups == groups.length) { 812 groups = Arrays.copyOf(groups, ngroups * 2); 813 } 814 groups[ngroups] = g; 815 816 // This is done last so it doesn't matter in case the 817 // thread is killed 818 ngroups++; 819 } 820 } 821 822 /** 823 * Removes the specified Thread group from this group. 824 * @param g the Thread group to be removed 825 * @return if this Thread has already been destroyed. 826 */ remove(ThreadGroup g)827 private void remove(ThreadGroup g) { 828 synchronized (this) { 829 if (destroyed) { 830 return; 831 } 832 for (int i = 0 ; i < ngroups ; i++) { 833 if (groups[i] == g) { 834 ngroups -= 1; 835 System.arraycopy(groups, i + 1, groups, i, ngroups - i); 836 // Zap dangling reference to the dead group so that 837 // the garbage collector will collect it. 838 groups[ngroups] = null; 839 break; 840 } 841 } 842 if (nthreads == 0) { 843 notifyAll(); 844 } 845 if (daemon && (nthreads == 0) && 846 (nUnstartedThreads == 0) && (ngroups == 0)) 847 { 848 destroy(); 849 } 850 } 851 } 852 853 854 /** 855 * Increments the count of unstarted threads in the thread group. 856 * Unstarted threads are not added to the thread group so that they 857 * can be collected if they are never started, but they must be 858 * counted so that daemon thread groups with unstarted threads in 859 * them are not destroyed. 860 */ addUnstarted()861 void addUnstarted() { 862 synchronized(this) { 863 if (destroyed) { 864 throw new IllegalThreadStateException(); 865 } 866 nUnstartedThreads++; 867 } 868 } 869 870 /** 871 * Adds the specified thread to this thread group. 872 * 873 * <p> Note: This method is called from both library code 874 * and the Virtual Machine. It is called from VM to add 875 * certain system threads to the system thread group. 876 * 877 * @param t 878 * the Thread to be added 879 * 880 * @throws IllegalThreadStateException 881 * if the Thread group has been destroyed 882 */ add(Thread t)883 void add(Thread t) { 884 synchronized (this) { 885 if (destroyed) { 886 throw new IllegalThreadStateException(); 887 } 888 if (threads == null) { 889 threads = new Thread[4]; 890 } else if (nthreads == threads.length) { 891 threads = Arrays.copyOf(threads, nthreads * 2); 892 } 893 threads[nthreads] = t; 894 895 // This is done last so it doesn't matter in case the 896 // thread is killed 897 nthreads++; 898 899 // The thread is now a fully fledged member of the group, even 900 // though it may, or may not, have been started yet. It will prevent 901 // the group from being destroyed so the unstarted Threads count is 902 // decremented. 903 nUnstartedThreads--; 904 } 905 } 906 907 /** 908 * Notifies the group that the thread {@code t} has failed 909 * an attempt to start. 910 * 911 * <p> The state of this thread group is rolled back as if the 912 * attempt to start the thread has never occurred. The thread is again 913 * considered an unstarted member of the thread group, and a subsequent 914 * attempt to start the thread is permitted. 915 * 916 * @param t 917 * the Thread whose start method was invoked 918 */ threadStartFailed(Thread t)919 void threadStartFailed(Thread t) { 920 synchronized(this) { 921 remove(t); 922 nUnstartedThreads++; 923 } 924 } 925 926 /** 927 * Notifies the group that the thread {@code t} has terminated. 928 * 929 * <p> Destroy the group if all of the following conditions are 930 * true: this is a daemon thread group; there are no more alive 931 * or unstarted threads in the group; there are no subgroups in 932 * this thread group. 933 * 934 * @param t 935 * the Thread that has terminated 936 */ threadTerminated(Thread t)937 void threadTerminated(Thread t) { 938 synchronized (this) { 939 remove(t); 940 941 if (nthreads == 0) { 942 notifyAll(); 943 } 944 if (daemon && (nthreads == 0) && 945 (nUnstartedThreads == 0) && (ngroups == 0)) 946 { 947 destroy(); 948 } 949 } 950 } 951 952 /** 953 * Removes the specified Thread from this group. Invoking this method 954 * on a thread group that has been destroyed has no effect. 955 * 956 * @param t 957 * the Thread to be removed 958 */ remove(Thread t)959 private void remove(Thread t) { 960 synchronized (this) { 961 if (destroyed) { 962 return; 963 } 964 for (int i = 0 ; i < nthreads ; i++) { 965 if (threads[i] == t) { 966 System.arraycopy(threads, i + 1, threads, i, --nthreads - i); 967 // Zap dangling reference to the dead thread so that 968 // the garbage collector will collect it. 969 threads[nthreads] = null; 970 break; 971 } 972 } 973 } 974 } 975 976 /** 977 * Prints information about this thread group to the standard 978 * output. This method is useful only for debugging. 979 * 980 * @since 1.0 981 */ list()982 public void list() { 983 list(System.out, 0); 984 } list(PrintStream out, int indent)985 void list(PrintStream out, int indent) { 986 int ngroupsSnapshot; 987 ThreadGroup[] groupsSnapshot; 988 synchronized (this) { 989 for (int j = 0 ; j < indent ; j++) { 990 out.print(" "); 991 } 992 out.println(this); 993 indent += 4; 994 for (int i = 0 ; i < nthreads ; i++) { 995 for (int j = 0 ; j < indent ; j++) { 996 out.print(" "); 997 } 998 out.println(threads[i]); 999 } 1000 ngroupsSnapshot = ngroups; 1001 if (groups != null) { 1002 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 1003 } else { 1004 groupsSnapshot = null; 1005 } 1006 } 1007 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 1008 groupsSnapshot[i].list(out, indent); 1009 } 1010 } 1011 1012 /** 1013 * Called by the Java Virtual Machine when a thread in this 1014 * thread group stops because of an uncaught exception, and the thread 1015 * does not have a specific {@link Thread.UncaughtExceptionHandler} 1016 * installed. 1017 * <p> 1018 * The {@code uncaughtException} method of 1019 * {@code ThreadGroup} does the following: 1020 * <ul> 1021 * <li>If this thread group has a parent thread group, the 1022 * {@code uncaughtException} method of that parent is called 1023 * with the same two arguments. 1024 * <li>Otherwise, this method checks to see if there is a 1025 * {@linkplain Thread#getDefaultUncaughtExceptionHandler default 1026 * uncaught exception handler} installed, and if so, its 1027 * {@code uncaughtException} method is called with the same 1028 * two arguments. 1029 * <li>Otherwise, this method determines if the {@code Throwable} 1030 * argument is an instance of {@link ThreadDeath}. If so, nothing 1031 * special is done. Otherwise, a message containing the 1032 * thread's name, as returned from the thread's {@link 1033 * Thread#getName getName} method, and a stack backtrace, 1034 * using the {@code Throwable}'s {@link 1035 * Throwable#printStackTrace printStackTrace} method, is 1036 * printed to the {@linkplain System#err standard error stream}. 1037 * </ul> 1038 * <p> 1039 * Applications can override this method in subclasses of 1040 * {@code ThreadGroup} to provide alternative handling of 1041 * uncaught exceptions. 1042 * 1043 * @param t the thread that is about to exit. 1044 * @param e the uncaught exception. 1045 * @since 1.0 1046 */ uncaughtException(Thread t, Throwable e)1047 public void uncaughtException(Thread t, Throwable e) { 1048 if (parent != null) { 1049 parent.uncaughtException(t, e); 1050 } else { 1051 Thread.UncaughtExceptionHandler ueh = 1052 Thread.getDefaultUncaughtExceptionHandler(); 1053 if (ueh != null) { 1054 ueh.uncaughtException(t, e); 1055 } else if (!(e instanceof ThreadDeath)) { 1056 System.err.print("Exception in thread \"" 1057 + t.getName() + "\" "); 1058 e.printStackTrace(System.err); 1059 } 1060 } 1061 } 1062 1063 /** 1064 * Used by VM to control lowmem implicit suspension. 1065 * 1066 * @param b boolean to allow or disallow suspension 1067 * @return true on success 1068 * @since 1.1 1069 * @deprecated The definition of this call depends on {@link #suspend}, 1070 * which is deprecated. Further, the behavior of this call 1071 * was never specified. 1072 */ 1073 @Deprecated(since="1.2") allowThreadSuspension(boolean b)1074 public boolean allowThreadSuspension(boolean b) { 1075 return true; 1076 } 1077 1078 /** 1079 * Returns a string representation of this Thread group. 1080 * 1081 * @return a string representation of this thread group. 1082 * @since 1.0 1083 */ toString()1084 public String toString() { 1085 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]"; 1086 } 1087 } 1088