Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]
    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   }

Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]