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