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