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