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