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