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