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

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

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