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