1 /* 2 * Copyright (c) 1995, 2010, 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 import sun.misc.VM; 31 32 /** 33 * A thread group represents a set of threads. In addition, a thread 34 * group can also include other thread groups. The thread groups form 35 * a tree in which every thread group except the initial thread group 36 * has a parent. 37 * <p> 38 * A thread is allowed to access information about its own thread 39 * group, but not to access information about its thread group's 40 * parent thread group or any other thread groups. 41 * 42 * @author unascribed 43 * @since JDK1.0 44 */ 45 /* The locking strategy for this code is to try to lock only one level of the 46 * tree wherever possible, but otherwise to lock from the bottom up. 47 * That is, from child thread groups to parents. 48 * This has the advantage of limiting the number of locks that need to be held 49 * and in particular avoids having to grab the lock for the root thread group, 50 * (or a global lock) which would be a source of contention on a 51 * multi-processor system with many thread groups. 52 * This policy often leads to taking a snapshot of the state of a thread group 53 * and working off of that snapshot, rather than holding the thread group locked 54 * while we work on the children. 55 */ 56 public 57 class ThreadGroup implements Thread.UncaughtExceptionHandler { 58 private final ThreadGroup parent; 59 String name; 60 int maxPriority; 61 boolean destroyed; 62 boolean daemon; 63 boolean vmAllowSuspension; 64 65 int nUnstartedThreads = 0; 66 int nthreads; 67 Thread threads[]; 68 69 int ngroups; 70 ThreadGroup groups[]; 71 72 /** 73 * Creates an empty Thread group that is not in any Thread group. 74 * This method is used to create the system Thread group. 75 */ 76 private ThreadGroup() { // called from C code 77 this.name = "system"; 78 this.maxPriority = Thread.MAX_PRIORITY; 79 this.parent = null; 80 } 81 82 /** 83 * Constructs a new thread group. The parent of this new group is 84 * the thread group of the currently running thread. 85 * <p> 86 * The <code>checkAccess</code> method of the parent thread group is 87 * called with no arguments; this may result in a security exception. 88 * 89 * @param name the name of the new thread group. 90 * @exception SecurityException if the current thread cannot create a 91 * thread in the specified thread group. 92 * @see java.lang.ThreadGroup#checkAccess() 93 * @since JDK1.0 94 */ 95 public ThreadGroup(String name) { 96 this(Thread.currentThread().getThreadGroup(), name); 97 } 98 99 /** 100 * Creates a new thread group. The parent of this new group is the 101 * specified thread group. 102 * <p> 103 * The <code>checkAccess</code> method of the parent thread group is 104 * called with no arguments; this may result in a security exception. 105 * 106 * @param parent the parent thread group. 107 * @param name the name of the new thread group. 108 * @exception NullPointerException if the thread group argument is 109 * <code>null</code>. 110 * @exception SecurityException if the current thread cannot create a 111 * thread in the specified thread group. 112 * @see java.lang.SecurityException 113 * @see java.lang.ThreadGroup#checkAccess() 114 * @since JDK1.0 115 */ 116 public ThreadGroup(ThreadGroup parent, String name) { 117 this(checkParentAccess(parent), parent, name); 118 } 119 120 private ThreadGroup(Void unused, ThreadGroup parent, String name) { 121 this.name = name; 122 this.maxPriority = parent.maxPriority; 123 this.daemon = parent.daemon; 124 this.vmAllowSuspension = parent.vmAllowSuspension; 125 this.parent = parent; 126 parent.add(this); 127 } 128 129 /* 130 * @throws NullPointerException if the parent argument is {@code null} 131 * @throws SecurityException if the current thread cannot create a 132 * thread in the specified thread group. 133 */ 134 private static Void checkParentAccess(ThreadGroup parent) { 135 parent.checkAccess(); 136 return null; 137 } 138 139 /** 140 * Returns the name of this thread group. 141 * 142 * @return the name of this thread group. 143 * @since JDK1.0 144 */ 145 public final String getName() { 146 return name; 147 } 148 149 /** 150 * Returns the parent of this thread group. 151 * <p> 152 * First, if the parent is not <code>null</code>, the 153 * <code>checkAccess</code> method of the parent thread group is 154 * called with no arguments; this may result in a security exception. 155 * 156 * @return the parent of this thread group. The top-level thread group 157 * is the only thread group whose parent is <code>null</code>. 158 * @exception SecurityException if the current thread cannot modify 159 * this thread group. 160 * @see java.lang.ThreadGroup#checkAccess() 161 * @see java.lang.SecurityException 162 * @see java.lang.RuntimePermission 163 * @since JDK1.0 164 */ 165 public final ThreadGroup getParent() { 166 if (parent != null) 167 parent.checkAccess(); 168 return parent; 169 } 170 171 /** 172 * Returns the maximum priority of this thread group. Threads that are 173 * part of this group cannot have a higher priority than the maximum 174 * priority. 175 * 176 * @return the maximum priority that a thread in this thread group 177 * can have. 178 * @see #setMaxPriority 179 * @since JDK1.0 180 */ 181 public final int getMaxPriority() { 182 return maxPriority; 183 } 184 185 /** 186 * Tests if this thread group is a daemon thread group. A 187 * daemon thread group is automatically destroyed when its last 188 * thread is stopped or its last thread group is destroyed. 189 * 190 * @return <code>true</code> if this thread group is a daemon thread group; 191 * <code>false</code> otherwise. 192 * @since JDK1.0 193 */ 194 public final boolean isDaemon() { 195 return daemon; 196 } 197 198 /** 199 * Tests if this thread group has been destroyed. 200 * 201 * @return true if this object is destroyed 202 * @since JDK1.1 203 */ 204 public synchronized boolean isDestroyed() { 205 return destroyed; 206 } 207 208 /** 209 * Changes the daemon status of this thread group. 210 * <p> 211 * First, the <code>checkAccess</code> method of this thread group is 212 * called with no arguments; this may result in a security exception. 213 * <p> 214 * A daemon thread group is automatically destroyed when its last 215 * thread is stopped or its last thread group is destroyed. 216 * 217 * @param daemon if <code>true</code>, marks this thread group as 218 * a daemon thread group; otherwise, marks this 219 * thread group as normal. 220 * @exception SecurityException if the current thread cannot modify 221 * this thread group. 222 * @see java.lang.SecurityException 223 * @see java.lang.ThreadGroup#checkAccess() 224 * @since JDK1.0 225 */ 226 public final void setDaemon(boolean daemon) { 227 checkAccess(); 228 this.daemon = daemon; 229 } 230 231 /** 232 * Sets the maximum priority of the group. Threads in the thread 233 * group that already have a higher priority are not affected. 234 * <p> 235 * First, the <code>checkAccess</code> method of this thread group is 236 * called with no arguments; this may result in a security exception. 237 * <p> 238 * If the <code>pri</code> argument is less than 239 * {@link Thread#MIN_PRIORITY} or greater than 240 * {@link Thread#MAX_PRIORITY}, the maximum priority of the group 241 * remains unchanged. 242 * <p> 243 * Otherwise, the priority of this ThreadGroup object is set to the 244 * smaller of the specified <code>pri</code> and the maximum permitted 245 * priority of the parent of this thread group. (If this thread group 246 * is the system thread group, which has no parent, then its maximum 247 * priority is simply set to <code>pri</code>.) Then this method is 248 * called recursively, with <code>pri</code> as its argument, for 249 * every thread group that belongs to this thread group. 250 * 251 * @param pri the new priority of the thread group. 252 * @exception SecurityException if the current thread cannot modify 253 * this thread group. 254 * @see #getMaxPriority 255 * @see java.lang.SecurityException 256 * @see java.lang.ThreadGroup#checkAccess() 257 * @since JDK1.0 258 */ 259 public final void setMaxPriority(int pri) { 260 int ngroupsSnapshot; 261 ThreadGroup[] groupsSnapshot; 262 synchronized (this) { 263 checkAccess(); 264 if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) { 265 return; 266 } 267 maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri; 268 ngroupsSnapshot = ngroups; 269 if (groups != null) { 270 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 271 } else { 272 groupsSnapshot = null; 273 } 274 } 275 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 276 groupsSnapshot[i].setMaxPriority(pri); 277 } 278 } 279 280 /** 281 * Tests if this thread group is either the thread group 282 * argument or one of its ancestor thread groups. 283 * 284 * @param g a thread group. 285 * @return <code>true</code> if this thread group is the thread group 286 * argument or one of its ancestor thread groups; 287 * <code>false</code> otherwise. 288 * @since JDK1.0 289 */ 290 public final boolean parentOf(ThreadGroup g) { 291 for (; g != null ; g = g.parent) { 292 if (g == this) { 293 return true; 294 } 295 } 296 return false; 297 } 298 299 /** 300 * Determines if the currently running thread has permission to 301 * modify this thread group. 302 * <p> 303 * If there is a security manager, its <code>checkAccess</code> method 304 * is called with this thread group as its argument. This may result 305 * in throwing a <code>SecurityException</code>. 306 * 307 * @exception SecurityException if the current thread is not allowed to 308 * access this thread group. 309 * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup) 310 * @since JDK1.0 311 */ 312 public final void checkAccess() { 313 SecurityManager security = System.getSecurityManager(); 314 if (security != null) { 315 security.checkAccess(this); 316 } 317 } 318 319 /** 320 * Returns an estimate of the number of active threads in this thread 321 * group and its subgroups. Recursively iterates over all subgroups in 322 * this thread group. 323 * 324 * <p> The value returned is only an estimate because the number of 325 * threads may change dynamically while this method traverses internal 326 * data structures, and might be affected by the presence of certain 327 * system threads. This method is intended primarily for debugging 328 * and monitoring purposes. 329 * 330 * @return an estimate of the number of active threads in this thread 331 * group and in any other thread group that has this thread 332 * group as an ancestor 333 * 334 * @since JDK1.0 335 */ 336 public int activeCount() { 337 int result; 338 // Snapshot sub-group data so we don't hold this lock 339 // while our children are computing. 340 int ngroupsSnapshot; 341 ThreadGroup[] groupsSnapshot; 342 synchronized (this) { 343 if (destroyed) { 344 return 0; 345 } 346 result = nthreads; 347 ngroupsSnapshot = ngroups; 348 if (groups != null) { 349 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 350 } else { 351 groupsSnapshot = null; 352 } 353 } 354 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 355 result += groupsSnapshot[i].activeCount(); 356 } 357 return result; 358 } 359 360 /** 361 * Copies into the specified array every active thread in this 362 * thread group and its subgroups. 363 * 364 * <p> An invocation of this method behaves in exactly the same 365 * way as the invocation 366 * 367 * <blockquote> 368 * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)} 369 * </blockquote> 370 * 371 * @param list 372 * an array into which to put the list of threads 373 * 374 * @return the number of threads put into the array 375 * 376 * @throws SecurityException 377 * if {@linkplain #checkAccess checkAccess} determines that 378 * the current thread cannot access this thread group 379 * 380 * @since JDK1.0 381 */ 382 public int enumerate(Thread list[]) { 383 checkAccess(); 384 return enumerate(list, 0, true); 385 } 386 387 /** 388 * Copies into the specified array every active thread in this 389 * thread group. If {@code recurse} is {@code true}, 390 * this method recursively enumerates all subgroups of this 391 * thread group and references to every active thread in these 392 * subgroups are also included. If the array is too short to 393 * hold all the threads, the extra threads are silently ignored. 394 * 395 * <p> An application might use the {@linkplain #activeCount activeCount} 396 * method to get an estimate of how big the array should be, however 397 * <i>if the array is too short to hold all the threads, the extra threads 398 * are silently ignored.</i> If it is critical to obtain every active 399 * thread in this thread group, the caller should verify that the returned 400 * int value is strictly less than the length of {@code list}. 401 * 402 * <p> Due to the inherent race condition in this method, it is recommended 403 * that the method only be used for debugging and monitoring purposes. 404 * 405 * @param list 406 * an array into which to put the list of threads 407 * 408 * @param recurse 409 * if {@code true}, recursively enumerate all subgroups of this 410 * thread group 411 * 412 * @return the number of threads put into the array 413 * 414 * @throws SecurityException 415 * if {@linkplain #checkAccess checkAccess} determines that 416 * the current thread cannot access this thread group 417 * 418 * @since JDK1.0 419 */ 420 public int enumerate(Thread list[], boolean recurse) { 421 checkAccess(); 422 return enumerate(list, 0, recurse); 423 } 424 425 private int enumerate(Thread list[], int n, boolean recurse) { 426 int ngroupsSnapshot = 0; 427 ThreadGroup[] groupsSnapshot = null; 428 synchronized (this) { 429 if (destroyed) { 430 return 0; 431 } 432 int nt = nthreads; 433 if (nt > list.length - n) { 434 nt = list.length - n; 435 } 436 for (int i = 0; i < nt; i++) { 437 if (threads[i].isAlive()) { 438 list[n++] = threads[i]; 439 } 440 } 441 if (recurse) { 442 ngroupsSnapshot = ngroups; 443 if (groups != null) { 444 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 445 } else { 446 groupsSnapshot = null; 447 } 448 } 449 } 450 if (recurse) { 451 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 452 n = groupsSnapshot[i].enumerate(list, n, true); 453 } 454 } 455 return n; 456 } 457 458 /** 459 * Returns an estimate of the number of active groups in this 460 * thread group and its subgroups. Recursively iterates over 461 * all subgroups in this thread group. 462 * 463 * <p> The value returned is only an estimate because the number of 464 * thread groups may change dynamically while this method traverses 465 * internal data structures. This method is intended primarily for 466 * debugging and monitoring purposes. 467 * 468 * @return the number of active thread groups with this thread group as 469 * an ancestor 470 * 471 * @since JDK1.0 472 */ 473 public int activeGroupCount() { 474 int ngroupsSnapshot; 475 ThreadGroup[] groupsSnapshot; 476 synchronized (this) { 477 if (destroyed) { 478 return 0; 479 } 480 ngroupsSnapshot = ngroups; 481 if (groups != null) { 482 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 483 } else { 484 groupsSnapshot = null; 485 } 486 } 487 int n = ngroupsSnapshot; 488 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 489 n += groupsSnapshot[i].activeGroupCount(); 490 } 491 return n; 492 } 493 494 /** 495 * Copies into the specified array references to every active 496 * subgroup in this thread group and its subgroups. 497 * 498 * <p> An invocation of this method behaves in exactly the same 499 * way as the invocation 500 * 501 * <blockquote> 502 * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)} 503 * </blockquote> 504 * 505 * @param list 506 * an array into which to put the list of thread groups 507 * 508 * @return the number of thread groups put into the array 509 * 510 * @throws SecurityException 511 * if {@linkplain #checkAccess checkAccess} determines that 512 * the current thread cannot access this thread group 513 * 514 * @since JDK1.0 515 */ 516 public int enumerate(ThreadGroup list[]) { 517 checkAccess(); 518 return enumerate(list, 0, true); 519 } 520 521 /** 522 * Copies into the specified array references to every active 523 * subgroup in this thread group. If {@code recurse} is 524 * {@code true}, this method recursively enumerates all subgroups of this 525 * thread group and references to every active thread group in these 526 * subgroups are also included. 527 * 528 * <p> An application might use the 529 * {@linkplain #activeGroupCount activeGroupCount} method to 530 * get an estimate of how big the array should be, however <i>if the 531 * array is too short to hold all the thread groups, the extra thread 532 * groups are silently ignored.</i> If it is critical to obtain every 533 * active subgroup in this thread group, the caller should verify that 534 * the returned int value is strictly less than the length of 535 * {@code list}. 536 * 537 * <p> Due to the inherent race condition in this method, it is recommended 538 * that the method only be used for debugging and monitoring purposes. 539 * 540 * @param list 541 * an array into which to put the list of thread groups 542 * 543 * @param recurse 544 * if {@code true}, recursively enumerate all subgroups 545 * 546 * @return the number of thread groups put into the array 547 * 548 * @throws SecurityException 549 * if {@linkplain #checkAccess checkAccess} determines that 550 * the current thread cannot access this thread group 551 * 552 * @since JDK1.0 553 */ 554 public int enumerate(ThreadGroup list[], boolean recurse) { 555 checkAccess(); 556 return enumerate(list, 0, recurse); 557 } 558 559 private int enumerate(ThreadGroup list[], int n, boolean recurse) { 560 int ngroupsSnapshot = 0; 561 ThreadGroup[] groupsSnapshot = null; 562 synchronized (this) { 563 if (destroyed) { 564 return 0; 565 } 566 int ng = ngroups; 567 if (ng > list.length - n) { 568 ng = list.length - n; 569 } 570 if (ng > 0) { 571 System.arraycopy(groups, 0, list, n, ng); 572 n += ng; 573 } 574 if (recurse) { 575 ngroupsSnapshot = ngroups; 576 if (groups != null) { 577 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 578 } else { 579 groupsSnapshot = null; 580 } 581 } 582 } 583 if (recurse) { 584 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 585 n = groupsSnapshot[i].enumerate(list, n, true); 586 } 587 } 588 return n; 589 } 590 591 /** 592 * Stops all threads in this thread group. 593 * <p> 594 * First, the <code>checkAccess</code> method of this thread group is 595 * called with no arguments; this may result in a security exception. 596 * <p> 597 * This method then calls the <code>stop</code> method on all the 598 * threads in this thread group and in all of its subgroups. 599 * 600 * @exception SecurityException if the current thread is not allowed 601 * to access this thread group or any of the threads in 602 * the thread group. 603 * @see java.lang.SecurityException 604 * @see java.lang.Thread#stop() 605 * @see java.lang.ThreadGroup#checkAccess() 606 * @since JDK1.0 607 * @deprecated This method is inherently unsafe. See 608 * {@link Thread#stop} for details. 609 */ 610 @Deprecated 611 public final void stop() { 612 if (stopOrSuspend(false)) 613 Thread.currentThread().stop(); 614 } 615 616 /** 617 * Interrupts all threads in this thread group. 618 * <p> 619 * First, the <code>checkAccess</code> method of this thread group is 620 * called with no arguments; this may result in a security exception. 621 * <p> 622 * This method then calls the <code>interrupt</code> method on all the 623 * threads in this thread group and in all of its subgroups. 624 * 625 * @exception SecurityException if the current thread is not allowed 626 * to access this thread group or any of the threads in 627 * the thread group. 628 * @see java.lang.Thread#interrupt() 629 * @see java.lang.SecurityException 630 * @see java.lang.ThreadGroup#checkAccess() 631 * @since 1.2 632 */ 633 public final void interrupt() { 634 int ngroupsSnapshot; 635 ThreadGroup[] groupsSnapshot; 636 synchronized (this) { 637 checkAccess(); 638 for (int i = 0 ; i < nthreads ; i++) { 639 threads[i].interrupt(); 640 } 641 ngroupsSnapshot = ngroups; 642 if (groups != null) { 643 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 644 } else { 645 groupsSnapshot = null; 646 } 647 } 648 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 649 groupsSnapshot[i].interrupt(); 650 } 651 } 652 653 /** 654 * Suspends all threads in this thread group. 655 * <p> 656 * First, the <code>checkAccess</code> method of this thread group is 657 * called with no arguments; this may result in a security exception. 658 * <p> 659 * This method then calls the <code>suspend</code> method on all the 660 * threads in this thread group and in all of its subgroups. 661 * 662 * @exception SecurityException if the current thread is not allowed 663 * to access this thread group or any of the threads in 664 * the thread group. 665 * @see java.lang.Thread#suspend() 666 * @see java.lang.SecurityException 667 * @see java.lang.ThreadGroup#checkAccess() 668 * @since JDK1.0 669 * @deprecated This method is inherently deadlock-prone. See 670 * {@link Thread#suspend} for details. 671 */ 672 @Deprecated 673 public final void suspend() { 674 if (stopOrSuspend(true)) 675 Thread.currentThread().suspend(); 676 } 677 678 /** 679 * Helper method: recursively stops or suspends (as directed by the 680 * boolean argument) all of the threads in this thread group and its 681 * subgroups, except the current thread. This method returns true 682 * if (and only if) the current thread is found to be in this thread 683 * group or one of its subgroups. 684 */ 685 private boolean stopOrSuspend(boolean suspend) { 686 boolean suicide = false; 687 Thread us = Thread.currentThread(); 688 int ngroupsSnapshot; 689 ThreadGroup[] groupsSnapshot = null; 690 synchronized (this) { 691 checkAccess(); 692 for (int i = 0 ; i < nthreads ; i++) { 693 if (threads[i]==us) 694 suicide = true; 695 else if (suspend) 696 threads[i].suspend(); 697 else 698 threads[i].stop(); 699 } 700 701 ngroupsSnapshot = ngroups; 702 if (groups != null) { 703 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 704 } 705 } 706 for (int i = 0 ; i < ngroupsSnapshot ; i++) 707 suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide; 708 709 return suicide; 710 } 711 712 /** 713 * Resumes all threads in this thread group. 714 * <p> 715 * First, the <code>checkAccess</code> method of this thread group is 716 * called with no arguments; this may result in a security exception. 717 * <p> 718 * This method then calls the <code>resume</code> method on all the 719 * threads in this thread group and in all of its sub groups. 720 * 721 * @exception SecurityException if the current thread is not allowed to 722 * access this thread group or any of the threads in the 723 * thread group. 724 * @see java.lang.SecurityException 725 * @see java.lang.Thread#resume() 726 * @see java.lang.ThreadGroup#checkAccess() 727 * @since JDK1.0 728 * @deprecated This method is used solely in conjunction with 729 * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>, 730 * both of which have been deprecated, as they are inherently 731 * deadlock-prone. See {@link Thread#suspend} for details. 732 */ 733 @Deprecated 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</code> method of this thread group is 760 * called with no arguments; this may result in a security exception. 761 * 762 * @exception IllegalThreadStateException if the thread group is not 763 * empty or if the thread group has already been destroyed. 764 * @exception SecurityException if the current thread cannot modify this 765 * thread group. 766 * @see java.lang.ThreadGroup#checkAccess() 767 * @since JDK1.0 768 */ 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 * @exception IllegalThreadStateException If the Thread group has been destroyed. 803 */ 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 */ 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 */ 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 */ 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 * 919 * @param failed 920 * true if the thread could not be started successfully 921 */ 922 void threadStartFailed(Thread t) { 923 synchronized(this) { 924 remove(t); 925 nUnstartedThreads++; 926 } 927 } 928 929 /** 930 * Notifies the group that the thread {@code t} has terminated. 931 * 932 * <p> Destroy the group if all of the following conditions are 933 * true: this is a daemon thread group; there are no more alive 934 * or unstarted threads in the group; there are no subgroups in 935 * this thread group. 936 * 937 * @param t 938 * the Thread that has terminated 939 */ 940 void threadTerminated(Thread t) { 941 synchronized (this) { 942 remove(t); 943 944 if (nthreads == 0) { 945 notifyAll(); 946 } 947 if (daemon && (nthreads == 0) && 948 (nUnstartedThreads == 0) && (ngroups == 0)) 949 { 950 destroy(); 951 } 952 } 953 } 954 955 /** 956 * Removes the specified Thread from this group. Invoking this method 957 * on a thread group that has been destroyed has no effect. 958 * 959 * @param t 960 * the Thread to be removed 961 */ 962 private void remove(Thread t) { 963 synchronized (this) { 964 if (destroyed) { 965 return; 966 } 967 for (int i = 0 ; i < nthreads ; i++) { 968 if (threads[i] == t) { 969 System.arraycopy(threads, i + 1, threads, i, --nthreads - i); 970 // Zap dangling reference to the dead thread so that 971 // the garbage collector will collect it. 972 threads[nthreads] = null; 973 break; 974 } 975 } 976 } 977 } 978 979 /** 980 * Prints information about this thread group to the standard 981 * output. This method is useful only for debugging. 982 * 983 * @since JDK1.0 984 */ 985 public void list() { 986 list(System.out, 0); 987 } 988 void list(PrintStream out, int indent) { 989 int ngroupsSnapshot; 990 ThreadGroup[] groupsSnapshot; 991 synchronized (this) { 992 for (int j = 0 ; j < indent ; j++) { 993 out.print(" "); 994 } 995 out.println(this); 996 indent += 4; 997 for (int i = 0 ; i < nthreads ; i++) { 998 for (int j = 0 ; j < indent ; j++) { 999 out.print(" "); 1000 } 1001 out.println(threads[i]); 1002 } 1003 ngroupsSnapshot = ngroups; 1004 if (groups != null) { 1005 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 1006 } else { 1007 groupsSnapshot = null; 1008 } 1009 } 1010 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 1011 groupsSnapshot[i].list(out, indent); 1012 } 1013 } 1014 1015 /** 1016 * Called by the Java Virtual Machine when a thread in this 1017 * thread group stops because of an uncaught exception, and the thread 1018 * does not have a specific {@link Thread.UncaughtExceptionHandler} 1019 * installed. 1020 * <p> 1021 * The <code>uncaughtException</code> method of 1022 * <code>ThreadGroup</code> does the following: 1023 * <ul> 1024 * <li>If this thread group has a parent thread group, the 1025 * <code>uncaughtException</code> method of that parent is called 1026 * with the same two arguments. 1027 * <li>Otherwise, this method checks to see if there is a 1028 * {@linkplain Thread#getDefaultUncaughtExceptionHandler default 1029 * uncaught exception handler} installed, and if so, its 1030 * <code>uncaughtException</code> method is called with the same 1031 * two arguments. 1032 * <li>Otherwise, this method determines if the <code>Throwable</code> 1033 * argument is an instance of {@link ThreadDeath}. If so, nothing 1034 * special is done. Otherwise, a message containing the 1035 * thread's name, as returned from the thread's {@link 1036 * Thread#getName getName} method, and a stack backtrace, 1037 * using the <code>Throwable</code>'s {@link 1038 * Throwable#printStackTrace printStackTrace} method, is 1039 * printed to the {@linkplain System#err standard error stream}. 1040 * </ul> 1041 * <p> 1042 * Applications can override this method in subclasses of 1043 * <code>ThreadGroup</code> to provide alternative handling of 1044 * uncaught exceptions. 1045 * 1046 * @param t the thread that is about to exit. 1047 * @param e the uncaught exception. 1048 * @since JDK1.0 1049 */ 1050 public void uncaughtException(Thread t, Throwable e) { 1051 if (parent != null) { 1052 parent.uncaughtException(t, e); 1053 } else { 1054 Thread.UncaughtExceptionHandler ueh = 1055 Thread.getDefaultUncaughtExceptionHandler(); 1056 if (ueh != null) { 1057 ueh.uncaughtException(t, e); 1058 } else if (!(e instanceof ThreadDeath)) { 1059 System.err.print("Exception in thread \"" 1060 + t.getName() + "\" "); 1061 e.printStackTrace(System.err); 1062 } 1063 } 1064 } 1065 1066 /** 1067 * Used by VM to control lowmem implicit suspension. 1068 * 1069 * @param b boolean to allow or disallow suspension 1070 * @return true on success 1071 * @since JDK1.1 1072 * @deprecated The definition of this call depends on {@link #suspend}, 1073 * which is deprecated. Further, the behavior of this call 1074 * was never specified. 1075 */ 1076 @Deprecated 1077 public boolean allowThreadSuspension(boolean b) { 1078 this.vmAllowSuspension = b; 1079 if (!b) { 1080 VM.unsuspendSomeThreads(); 1081 } 1082 return true; 1083 } 1084 1085 /** 1086 * Returns a string representation of this Thread group. 1087 * 1088 * @return a string representation of this thread group. 1089 * @since JDK1.0 1090 */ 1091 public String toString() { 1092 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]"; 1093 } 1094 }