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