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 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 */ setMaxPriority(int pri)264 public final void setMaxPriority(int pri) { 265 int ngroupsSnapshot; 266 ThreadGroup[] groupsSnapshot; 267 synchronized (this) { 268 checkAccess(); 269 // BEGIN Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY]. 270 // This preserves backward compatibility with previous versions of Android. 271 // if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) { 272 // return; 273 // } 274 if (pri < Thread.MIN_PRIORITY) { 275 pri = Thread.MIN_PRIORITY; 276 } 277 if (pri > Thread.MAX_PRIORITY) { 278 pri = Thread.MAX_PRIORITY; 279 } 280 // END Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY]. 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 // Android-removed: SecurityManager stubbed out on Android. 329 // SecurityManager security = System.getSecurityManager(); 330 // if (security != null) { 331 // security.checkAccess(this); 332 // } 333 } 334 335 /** 336 * Returns an estimate of the number of active threads in this thread 337 * group and its subgroups. Recursively iterates over all subgroups in 338 * this thread group. 339 * 340 * <p> The value returned is only an estimate because the number of 341 * threads may change dynamically while this method traverses internal 342 * data structures, and might be affected by the presence of certain 343 * system threads. This method is intended primarily for debugging 344 * and monitoring purposes. 345 * 346 * @return an estimate of the number of active threads in this thread 347 * group and in any other thread group that has this thread 348 * group as an ancestor 349 * 350 * @since JDK1.0 351 */ activeCount()352 public int activeCount() { 353 int result; 354 // Snapshot sub-group data so we don't hold this lock 355 // while our children are computing. 356 int ngroupsSnapshot; 357 ThreadGroup[] groupsSnapshot; 358 synchronized (this) { 359 if (destroyed) { 360 return 0; 361 } 362 result = nthreads; 363 ngroupsSnapshot = ngroups; 364 if (groups != null) { 365 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 366 } else { 367 groupsSnapshot = null; 368 } 369 } 370 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 371 result += groupsSnapshot[i].activeCount(); 372 } 373 return result; 374 } 375 376 /** 377 * Copies into the specified array every active thread in this 378 * thread group and its subgroups. 379 * 380 * <p> An invocation of this method behaves in exactly the same 381 * way as the invocation 382 * 383 * <blockquote> 384 * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)} 385 * </blockquote> 386 * 387 * @param list 388 * an array into which to put the list of threads 389 * 390 * @return the number of threads put into the array 391 * 392 * @throws SecurityException 393 * if {@linkplain #checkAccess checkAccess} determines that 394 * the current thread cannot access this thread group 395 * 396 * @since JDK1.0 397 */ enumerate(Thread list[])398 public int enumerate(Thread list[]) { 399 checkAccess(); 400 return enumerate(list, 0, true); 401 } 402 403 /** 404 * Copies into the specified array every active thread in this 405 * thread group. If {@code recurse} is {@code true}, 406 * this method recursively enumerates all subgroups of this 407 * thread group and references to every active thread in these 408 * subgroups are also included. If the array is too short to 409 * hold all the threads, the extra threads are silently ignored. 410 * 411 * <p> An application might use the {@linkplain #activeCount activeCount} 412 * method to get an estimate of how big the array should be, however 413 * <i>if the array is too short to hold all the threads, the extra threads 414 * are silently ignored.</i> If it is critical to obtain every active 415 * thread in this thread group, the caller should verify that the returned 416 * int value is strictly less than the length of {@code list}. 417 * 418 * <p> Due to the inherent race condition in this method, it is recommended 419 * that the method only be used for debugging and monitoring purposes. 420 * 421 * @param list 422 * an array into which to put the list of threads 423 * 424 * @param recurse 425 * if {@code true}, recursively enumerate all subgroups of this 426 * thread group 427 * 428 * @return the number of threads put into the array 429 * 430 * @throws SecurityException 431 * if {@linkplain #checkAccess checkAccess} determines that 432 * the current thread cannot access this thread group 433 * 434 * @since JDK1.0 435 */ enumerate(Thread list[], boolean recurse)436 public int enumerate(Thread list[], boolean recurse) { 437 checkAccess(); 438 return enumerate(list, 0, recurse); 439 } 440 enumerate(Thread list[], int n, boolean recurse)441 private int enumerate(Thread list[], int n, boolean recurse) { 442 int ngroupsSnapshot = 0; 443 ThreadGroup[] groupsSnapshot = null; 444 synchronized (this) { 445 if (destroyed) { 446 return 0; 447 } 448 int nt = nthreads; 449 if (nt > list.length - n) { 450 nt = list.length - n; 451 } 452 for (int i = 0; i < nt; i++) { 453 if (threads[i].isAlive()) { 454 list[n++] = threads[i]; 455 } 456 } 457 if (recurse) { 458 ngroupsSnapshot = ngroups; 459 if (groups != null) { 460 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 461 } else { 462 groupsSnapshot = null; 463 } 464 } 465 } 466 if (recurse) { 467 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 468 n = groupsSnapshot[i].enumerate(list, n, true); 469 } 470 } 471 return n; 472 } 473 474 /** 475 * Returns an estimate of the number of active groups in this 476 * thread group and its subgroups. Recursively iterates over 477 * all subgroups in this thread group. 478 * 479 * <p> The value returned is only an estimate because the number of 480 * thread groups may change dynamically while this method traverses 481 * internal data structures. This method is intended primarily for 482 * debugging and monitoring purposes. 483 * 484 * @return the number of active thread groups with this thread group as 485 * an ancestor 486 * 487 * @since JDK1.0 488 */ activeGroupCount()489 public int activeGroupCount() { 490 int ngroupsSnapshot; 491 ThreadGroup[] groupsSnapshot; 492 synchronized (this) { 493 if (destroyed) { 494 return 0; 495 } 496 ngroupsSnapshot = ngroups; 497 if (groups != null) { 498 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 499 } else { 500 groupsSnapshot = null; 501 } 502 } 503 int n = ngroupsSnapshot; 504 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 505 n += groupsSnapshot[i].activeGroupCount(); 506 } 507 return n; 508 } 509 510 /** 511 * Copies into the specified array references to every active 512 * subgroup in this thread group and its subgroups. 513 * 514 * <p> An invocation of this method behaves in exactly the same 515 * way as the invocation 516 * 517 * <blockquote> 518 * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)} 519 * </blockquote> 520 * 521 * @param list 522 * an array into which to put the list of thread groups 523 * 524 * @return the number of thread groups put into the array 525 * 526 * @throws SecurityException 527 * if {@linkplain #checkAccess checkAccess} determines that 528 * the current thread cannot access this thread group 529 * 530 * @since JDK1.0 531 */ enumerate(ThreadGroup list[])532 public int enumerate(ThreadGroup list[]) { 533 checkAccess(); 534 return enumerate(list, 0, true); 535 } 536 537 /** 538 * Copies into the specified array references to every active 539 * subgroup in this thread group. If {@code recurse} is 540 * {@code true}, this method recursively enumerates all subgroups of this 541 * thread group and references to every active thread group in these 542 * subgroups are also included. 543 * 544 * <p> An application might use the 545 * {@linkplain #activeGroupCount activeGroupCount} method to 546 * get an estimate of how big the array should be, however <i>if the 547 * array is too short to hold all the thread groups, the extra thread 548 * groups are silently ignored.</i> If it is critical to obtain every 549 * active subgroup in this thread group, the caller should verify that 550 * the returned int value is strictly less than the length of 551 * {@code list}. 552 * 553 * <p> Due to the inherent race condition in this method, it is recommended 554 * that the method only be used for debugging and monitoring purposes. 555 * 556 * @param list 557 * an array into which to put the list of thread groups 558 * 559 * @param recurse 560 * if {@code true}, recursively enumerate all subgroups 561 * 562 * @return the number of thread groups put into the array 563 * 564 * @throws SecurityException 565 * if {@linkplain #checkAccess checkAccess} determines that 566 * the current thread cannot access this thread group 567 * 568 * @since JDK1.0 569 */ enumerate(ThreadGroup list[], boolean recurse)570 public int enumerate(ThreadGroup list[], boolean recurse) { 571 checkAccess(); 572 return enumerate(list, 0, recurse); 573 } 574 enumerate(ThreadGroup list[], int n, boolean recurse)575 private int enumerate(ThreadGroup list[], int n, boolean recurse) { 576 int ngroupsSnapshot = 0; 577 ThreadGroup[] groupsSnapshot = null; 578 synchronized (this) { 579 if (destroyed) { 580 return 0; 581 } 582 int ng = ngroups; 583 if (ng > list.length - n) { 584 ng = list.length - n; 585 } 586 if (ng > 0) { 587 System.arraycopy(groups, 0, list, n, ng); 588 n += ng; 589 } 590 if (recurse) { 591 ngroupsSnapshot = ngroups; 592 if (groups != null) { 593 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 594 } else { 595 groupsSnapshot = null; 596 } 597 } 598 } 599 if (recurse) { 600 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 601 n = groupsSnapshot[i].enumerate(list, n, true); 602 } 603 } 604 return n; 605 } 606 607 /** 608 * Stops all threads in this thread group. 609 * <p> 610 * First, the <code>checkAccess</code> method of this thread group is 611 * called with no arguments; this may result in a security exception. 612 * <p> 613 * This method then calls the <code>stop</code> method on all the 614 * threads in this thread group and in all of its subgroups. 615 * 616 * @exception SecurityException if the current thread is not allowed 617 * to access this thread group or any of the threads in 618 * the thread group. 619 * @see java.lang.SecurityException 620 * @see java.lang.Thread#stop() 621 * @see java.lang.ThreadGroup#checkAccess() 622 * @since JDK1.0 623 * @deprecated This method is inherently unsafe. See 624 * {@link Thread#stop} for details. 625 */ 626 @Deprecated stop()627 public final void stop() { 628 if (stopOrSuspend(false)) 629 Thread.currentThread().stop(); 630 } 631 632 /** 633 * Interrupts all threads in this thread group. 634 * <p> 635 * First, the <code>checkAccess</code> method of this thread group is 636 * called with no arguments; this may result in a security exception. 637 * <p> 638 * This method then calls the <code>interrupt</code> method on all the 639 * threads in this thread group and in all of its subgroups. 640 * 641 * @exception SecurityException if the current thread is not allowed 642 * to access this thread group or any of the threads in 643 * the thread group. 644 * @see java.lang.Thread#interrupt() 645 * @see java.lang.SecurityException 646 * @see java.lang.ThreadGroup#checkAccess() 647 * @since 1.2 648 */ interrupt()649 public final void interrupt() { 650 int ngroupsSnapshot; 651 ThreadGroup[] groupsSnapshot; 652 synchronized (this) { 653 checkAccess(); 654 for (int i = 0 ; i < nthreads ; i++) { 655 threads[i].interrupt(); 656 } 657 ngroupsSnapshot = ngroups; 658 if (groups != null) { 659 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 660 } else { 661 groupsSnapshot = null; 662 } 663 } 664 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 665 groupsSnapshot[i].interrupt(); 666 } 667 } 668 669 /** 670 * Suspends all threads in this thread group. 671 * <p> 672 * First, the <code>checkAccess</code> method of this thread group is 673 * called with no arguments; this may result in a security exception. 674 * <p> 675 * This method then calls the <code>suspend</code> method on all the 676 * threads in this thread group and in all of its subgroups. 677 * 678 * @exception SecurityException if the current thread is not allowed 679 * to access this thread group or any of the threads in 680 * the thread group. 681 * @see java.lang.Thread#suspend() 682 * @see java.lang.SecurityException 683 * @see java.lang.ThreadGroup#checkAccess() 684 * @since JDK1.0 685 * @deprecated This method is inherently deadlock-prone. See 686 * {@link Thread#suspend} for details. 687 */ 688 @Deprecated 689 @SuppressWarnings("deprecation") suspend()690 public final void suspend() { 691 if (stopOrSuspend(true)) 692 Thread.currentThread().suspend(); 693 } 694 695 /** 696 * Helper method: recursively stops or suspends (as directed by the 697 * boolean argument) all of the threads in this thread group and its 698 * subgroups, except the current thread. This method returns true 699 * if (and only if) the current thread is found to be in this thread 700 * group or one of its subgroups. 701 */ 702 @SuppressWarnings("deprecation") stopOrSuspend(boolean suspend)703 private boolean stopOrSuspend(boolean suspend) { 704 boolean suicide = false; 705 Thread us = Thread.currentThread(); 706 int ngroupsSnapshot; 707 ThreadGroup[] groupsSnapshot = null; 708 synchronized (this) { 709 checkAccess(); 710 for (int i = 0 ; i < nthreads ; i++) { 711 if (threads[i]==us) 712 suicide = true; 713 else if (suspend) 714 threads[i].suspend(); 715 else 716 threads[i].stop(); 717 } 718 719 ngroupsSnapshot = ngroups; 720 if (groups != null) { 721 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 722 } 723 } 724 for (int i = 0 ; i < ngroupsSnapshot ; i++) 725 suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide; 726 727 return suicide; 728 } 729 730 /** 731 * Resumes all threads in this thread group. 732 * <p> 733 * First, the <code>checkAccess</code> method of this thread group is 734 * called with no arguments; this may result in a security exception. 735 * <p> 736 * This method then calls the <code>resume</code> method on all the 737 * threads in this thread group and in all of its sub groups. 738 * 739 * @exception SecurityException if the current thread is not allowed to 740 * access this thread group or any of the threads in the 741 * thread group. 742 * @see java.lang.SecurityException 743 * @see java.lang.Thread#resume() 744 * @see java.lang.ThreadGroup#checkAccess() 745 * @since JDK1.0 746 * @deprecated This method is used solely in conjunction with 747 * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>, 748 * both of which have been deprecated, as they are inherently 749 * deadlock-prone. See {@link Thread#suspend} for details. 750 */ 751 @Deprecated 752 @SuppressWarnings("deprecation") resume()753 public final void resume() { 754 int ngroupsSnapshot; 755 ThreadGroup[] groupsSnapshot; 756 synchronized (this) { 757 checkAccess(); 758 for (int i = 0 ; i < nthreads ; i++) { 759 threads[i].resume(); 760 } 761 ngroupsSnapshot = ngroups; 762 if (groups != null) { 763 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 764 } else { 765 groupsSnapshot = null; 766 } 767 } 768 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 769 groupsSnapshot[i].resume(); 770 } 771 } 772 773 /** 774 * Destroys this thread group and all of its subgroups. This thread 775 * group must be empty, indicating that all threads that had been in 776 * this thread group have since stopped. 777 * <p> 778 * First, the <code>checkAccess</code> method of this thread group is 779 * called with no arguments; this may result in a security exception. 780 * 781 * @exception IllegalThreadStateException if the thread group is not 782 * empty or if the thread group has already been destroyed. 783 * @exception SecurityException if the current thread cannot modify this 784 * thread group. 785 * @see java.lang.ThreadGroup#checkAccess() 786 * @since JDK1.0 787 */ destroy()788 public final void destroy() { 789 int ngroupsSnapshot; 790 ThreadGroup[] groupsSnapshot; 791 synchronized (this) { 792 checkAccess(); 793 if (destroyed || (nthreads > 0)) { 794 throw new IllegalThreadStateException(); 795 } 796 ngroupsSnapshot = ngroups; 797 if (groups != null) { 798 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 799 } else { 800 groupsSnapshot = null; 801 } 802 if (parent != null) { 803 destroyed = true; 804 ngroups = 0; 805 groups = null; 806 nthreads = 0; 807 threads = null; 808 } 809 } 810 for (int i = 0 ; i < ngroupsSnapshot ; i += 1) { 811 groupsSnapshot[i].destroy(); 812 } 813 if (parent != null) { 814 parent.remove(this); 815 } 816 } 817 818 /** 819 * Adds the specified Thread group to this group. 820 * @param g the specified Thread group to be added 821 * @exception IllegalThreadStateException If the Thread group has been destroyed. 822 */ add(ThreadGroup g)823 private final void add(ThreadGroup g){ 824 synchronized (this) { 825 if (destroyed) { 826 throw new IllegalThreadStateException(); 827 } 828 if (groups == null) { 829 groups = new ThreadGroup[4]; 830 } else if (ngroups == groups.length) { 831 groups = Arrays.copyOf(groups, ngroups * 2); 832 } 833 groups[ngroups] = g; 834 835 // This is done last so it doesn't matter in case the 836 // thread is killed 837 ngroups++; 838 } 839 } 840 841 /** 842 * Removes the specified Thread group from this group. 843 * @param g the Thread group to be removed 844 * @return if this Thread has already been destroyed. 845 */ remove(ThreadGroup g)846 private void remove(ThreadGroup g) { 847 synchronized (this) { 848 if (destroyed) { 849 return; 850 } 851 for (int i = 0 ; i < ngroups ; i++) { 852 if (groups[i] == g) { 853 ngroups -= 1; 854 System.arraycopy(groups, i + 1, groups, i, ngroups - i); 855 // Zap dangling reference to the dead group so that 856 // the garbage collector will collect it. 857 groups[ngroups] = null; 858 break; 859 } 860 } 861 if (nthreads == 0) { 862 notifyAll(); 863 } 864 if (daemon && (nthreads == 0) && 865 (nUnstartedThreads == 0) && (ngroups == 0)) 866 { 867 destroy(); 868 } 869 } 870 } 871 872 873 /** 874 * Increments the count of unstarted threads in the thread group. 875 * Unstarted threads are not added to the thread group so that they 876 * can be collected if they are never started, but they must be 877 * counted so that daemon thread groups with unstarted threads in 878 * them are not destroyed. 879 */ addUnstarted()880 void addUnstarted() { 881 synchronized(this) { 882 if (destroyed) { 883 throw new IllegalThreadStateException(); 884 } 885 nUnstartedThreads++; 886 } 887 } 888 889 /** 890 * Adds the specified thread to this thread group. 891 * 892 * <p> Note: This method is called from both library code 893 * and the Virtual Machine. It is called from VM to add 894 * certain system threads to the system thread group. 895 * 896 * @param t 897 * the Thread to be added 898 * 899 * @throws IllegalThreadStateException 900 * if the Thread group has been destroyed 901 */ add(Thread t)902 void add(Thread t) { 903 synchronized (this) { 904 if (destroyed) { 905 throw new IllegalThreadStateException(); 906 } 907 if (threads == null) { 908 threads = new Thread[4]; 909 } else if (nthreads == threads.length) { 910 threads = Arrays.copyOf(threads, nthreads * 2); 911 } 912 threads[nthreads] = t; 913 914 // This is done last so it doesn't matter in case the 915 // thread is killed 916 nthreads++; 917 918 // The thread is now a fully fledged member of the group, even 919 // though it may, or may not, have been started yet. It will prevent 920 // the group from being destroyed so the unstarted Threads count is 921 // decremented. 922 nUnstartedThreads--; 923 } 924 } 925 926 /** 927 * Notifies the group that the thread {@code t} has failed 928 * an attempt to start. 929 * 930 * <p> The state of this thread group is rolled back as if the 931 * attempt to start the thread has never occurred. The thread is again 932 * considered an unstarted member of the thread group, and a subsequent 933 * attempt to start the thread is permitted. 934 * 935 * @param t 936 * the Thread whose start method was invoked 937 */ threadStartFailed(Thread t)938 void threadStartFailed(Thread t) { 939 synchronized(this) { 940 remove(t); 941 nUnstartedThreads++; 942 } 943 } 944 945 /** 946 * Notifies the group that the thread {@code t} has terminated. 947 * 948 * <p> Destroy the group if all of the following conditions are 949 * true: this is a daemon thread group; there are no more alive 950 * or unstarted threads in the group; there are no subgroups in 951 * this thread group. 952 * 953 * @param t 954 * the Thread that has terminated 955 */ threadTerminated(Thread t)956 void threadTerminated(Thread t) { 957 synchronized (this) { 958 remove(t); 959 960 if (nthreads == 0) { 961 notifyAll(); 962 } 963 if (daemon && (nthreads == 0) && 964 (nUnstartedThreads == 0) && (ngroups == 0)) 965 { 966 destroy(); 967 } 968 } 969 } 970 971 /** 972 * Removes the specified Thread from this group. Invoking this method 973 * on a thread group that has been destroyed has no effect. 974 * 975 * @param t 976 * the Thread to be removed 977 */ remove(Thread t)978 private void remove(Thread t) { 979 synchronized (this) { 980 if (destroyed) { 981 return; 982 } 983 for (int i = 0 ; i < nthreads ; i++) { 984 if (threads[i] == t) { 985 System.arraycopy(threads, i + 1, threads, i, --nthreads - i); 986 // Zap dangling reference to the dead thread so that 987 // the garbage collector will collect it. 988 threads[nthreads] = null; 989 break; 990 } 991 } 992 } 993 } 994 995 /** 996 * Prints information about this thread group to the standard 997 * output. This method is useful only for debugging. 998 * 999 * @since JDK1.0 1000 */ list()1001 public void list() { 1002 list(System.out, 0); 1003 } list(PrintStream out, int indent)1004 void list(PrintStream out, int indent) { 1005 int ngroupsSnapshot; 1006 ThreadGroup[] groupsSnapshot; 1007 synchronized (this) { 1008 for (int j = 0 ; j < indent ; j++) { 1009 out.print(" "); 1010 } 1011 out.println(this); 1012 indent += 4; 1013 for (int i = 0 ; i < nthreads ; i++) { 1014 for (int j = 0 ; j < indent ; j++) { 1015 out.print(" "); 1016 } 1017 out.println(threads[i]); 1018 } 1019 ngroupsSnapshot = ngroups; 1020 if (groups != null) { 1021 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 1022 } else { 1023 groupsSnapshot = null; 1024 } 1025 } 1026 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 1027 groupsSnapshot[i].list(out, indent); 1028 } 1029 } 1030 1031 /** 1032 * Called by the Java Virtual Machine when a thread in this 1033 * thread group stops because of an uncaught exception, and the thread 1034 * does not have a specific {@link Thread.UncaughtExceptionHandler} 1035 * installed. 1036 * <p> 1037 * The <code>uncaughtException</code> method of 1038 * <code>ThreadGroup</code> does the following: 1039 * <ul> 1040 * <li>If this thread group has a parent thread group, the 1041 * <code>uncaughtException</code> method of that parent is called 1042 * with the same two arguments. 1043 * <li>Otherwise, this method checks to see if there is a 1044 * {@linkplain Thread#getDefaultUncaughtExceptionHandler default 1045 * uncaught exception handler} installed, and if so, its 1046 * <code>uncaughtException</code> method is called with the same 1047 * two arguments. 1048 * <li>Otherwise, this method determines if the <code>Throwable</code> 1049 * argument is an instance of {@link ThreadDeath}. If so, nothing 1050 * special is done. Otherwise, a message containing the 1051 * thread's name, as returned from the thread's {@link 1052 * Thread#getName getName} method, and a stack backtrace, 1053 * using the <code>Throwable</code>'s {@link 1054 * Throwable#printStackTrace printStackTrace} method, is 1055 * printed to the {@linkplain System#err standard error stream}. 1056 * </ul> 1057 * <p> 1058 * Applications can override this method in subclasses of 1059 * <code>ThreadGroup</code> to provide alternative handling of 1060 * uncaught exceptions. 1061 * 1062 * @param t the thread that is about to exit. 1063 * @param e the uncaught exception. 1064 * @since JDK1.0 1065 */ uncaughtException(Thread t, Throwable e)1066 public void uncaughtException(Thread t, Throwable e) { 1067 if (parent != null) { 1068 parent.uncaughtException(t, e); 1069 } else { 1070 Thread.UncaughtExceptionHandler ueh = 1071 Thread.getDefaultUncaughtExceptionHandler(); 1072 if (ueh != null) { 1073 ueh.uncaughtException(t, e); 1074 } else if (!(e instanceof ThreadDeath)) { 1075 System.err.print("Exception in thread \"" 1076 + t.getName() + "\" "); 1077 e.printStackTrace(System.err); 1078 } 1079 } 1080 } 1081 1082 /** 1083 * Used by VM to control lowmem implicit suspension. 1084 * 1085 * @param b boolean to allow or disallow suspension 1086 * @return true on success 1087 * @since JDK1.1 1088 * @deprecated The definition of this call depends on {@link #suspend}, 1089 * which is deprecated. Further, the behavior of this call 1090 * was never specified. 1091 */ 1092 @Deprecated allowThreadSuspension(boolean b)1093 public boolean allowThreadSuspension(boolean b) { 1094 this.vmAllowSuspension = b; 1095 if (!b) { 1096 VM.unsuspendSomeThreads(); 1097 } 1098 return true; 1099 } 1100 1101 /** 1102 * Returns a string representation of this Thread group. 1103 * 1104 * @return a string representation of this thread group. 1105 * @since JDK1.0 1106 */ toString()1107 public String toString() { 1108 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]"; 1109 } 1110 } 1111