home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / ThreadGroup.java < prev    next >
Text File  |  1997-05-20  |  27KB  |  841 lines

  1. /*
  2.  * @(#)ThreadGroup.java    1.32 97/02/20
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.lang;
  24.  
  25. import java.io.PrintStream;
  26. import sun.misc.VM;
  27.  
  28. /**
  29.  * A thread group represents a set of threads. In addition, a thread 
  30.  * group can also include other thread groups. The thread groups form 
  31.  * a tree in which every thread group except the initial thread group 
  32.  * has a parent. 
  33.  * <p>
  34.  * A thread is allowed to access information about its own thread 
  35.  * group, but not to access information about its thread group's 
  36.  * parent thread group or any other thread groups. 
  37.  *
  38.  * @author  unascribed
  39.  * @version 1.32, 02/20/97
  40.  * @since   JDK1.0
  41.  */
  42. /* The locking strategy for this code is to try to lock only one level of the
  43.  * tree wherever possible, but otherwise to lock from the bottom up.
  44.  * That is, from child thread groups to parents.
  45.  * This has the advantage of limiting the number of locks that need to be held
  46.  * and in particular avoids having to grab the lock for the root thread group,
  47.  * (or a global lock) which would be a source of contention on a 
  48.  * multi-processor system with many thread groups.
  49.  * This policy often leads to taking a snapshot of the state of a thread group
  50.  * and working off of that snapshot, rather than holding the thread group locked
  51.  * while we work on the children.
  52.  */
  53. public
  54. class ThreadGroup {
  55.     ThreadGroup parent;
  56.     String name;
  57.     int maxPriority;
  58.     boolean destroyed;
  59.     boolean daemon;
  60.     boolean vmAllowSuspension;
  61.  
  62.     int nthreads;
  63.     Thread threads[];
  64.  
  65.     int ngroups;
  66.     ThreadGroup groups[];
  67.  
  68.     /**
  69.      * Creates an empty Thread group that is not in any Thread group. 
  70.      * This method is used to create the system Thread group.
  71.      */
  72.     private ThreadGroup() {    // called from C code
  73.     this.name = "system";
  74.     this.maxPriority = Thread.MAX_PRIORITY;
  75.     }
  76.  
  77.     /**
  78.      * Constructs a new thread group. The parent of this new group is 
  79.      * the thread group of the currently running thread. 
  80.      *
  81.      * @param   name   the name of the new thread group.
  82.      * @since   JDK1.0
  83.      */
  84.     public ThreadGroup(String name) {
  85.     this(Thread.currentThread().getThreadGroup(), name);
  86.     }
  87.  
  88.     /**
  89.      * Creates a new thread group. The parent of this new group is the 
  90.      * specified thread group. 
  91.      * <p>
  92.      * The <code>checkAccess</code> method of the parent thread group is 
  93.      * called with no arguments; this may result in a security exception. 
  94.      *
  95.      * @param     parent   the parent thread group.
  96.      * @param     name     the name of the new thread group.
  97.      * @exception  NullPointerException  if the thread group argument is
  98.      *               <code>null</code>.
  99.      * @exception  SecurityException  if the current thread cannot create a
  100.      *               thread in the specified thread group.
  101.      * @see     java.lang.SecurityException
  102.      * @see     java.lang.ThreadGroup#checkAccess()
  103.      * @since   JDK1.0
  104.      */
  105.     public ThreadGroup(ThreadGroup parent, String name) {
  106.     if (parent == null) {
  107.         throw new NullPointerException();
  108.     }
  109.     parent.checkAccess();
  110.     this.name = name;
  111.     this.maxPriority = parent.maxPriority;
  112.     this.daemon = parent.daemon;
  113.     this.vmAllowSuspension = parent.vmAllowSuspension;
  114.     this.parent = parent;
  115.     parent.add(this);
  116.     }
  117.  
  118.     /**
  119.      * Returns the name of this thread group.
  120.      *
  121.      * @return  the name of this thread group.
  122.      * @since   JDK1.0
  123.      */
  124.     public final String getName() {
  125.     return name;
  126.     }
  127.  
  128.     /**
  129.      * Returns the parent of this thread group.
  130.      *
  131.      * @return  the parent of this thread group. The top-level thread group
  132.      *          is the only thread group whose parent is <code>null</code>.
  133.      * @since   JDK1.0
  134.      */
  135.     public final ThreadGroup getParent() {
  136.     return parent;
  137.     }
  138.  
  139.     /**
  140.      * Returns the maximum priority of this thread group. Threads that are
  141.      * part of this group cannot have a higher priority than the maximum
  142.      * priority.
  143.      *
  144.      * @return  the maximum priority that a thread in this thread group
  145.      *          can have.
  146.      * @since   JDK1.0
  147.      */
  148.     public final int getMaxPriority() {
  149.     return maxPriority;
  150.     }
  151.  
  152.     /**
  153.      * Tests if this thread group is a daemon thread group. A 
  154.      * daemon thread group is automatically destroyed when its last 
  155.      * thread is stopped or its last thread group is destroyed. 
  156.      *
  157.      * @return  <code>true</code> if this thread group is a daemon thread group;
  158.      *          <code>false</code> otherwise.
  159.      * @since   JDK1.0
  160.      */
  161.     public final boolean isDaemon() {
  162.     return daemon;
  163.     }
  164.  
  165.     /**
  166.      * Tests if this thread group has been destroyed.
  167.      *
  168.      * @since   JDK1.1
  169.      */
  170.     public synchronized boolean isDestroyed() {
  171.     return destroyed;
  172.     }
  173.  
  174.     /**
  175.      * Changes the daemon status of this thread group.
  176.      * <p>
  177.      * First, the <code>checkAccess</code> method of this thread group is 
  178.      * called with no arguments; this may result in a security exception. 
  179.      * <p>
  180.      * A daemon thread group is automatically destroyed when its last 
  181.      * thread is stopped or its last thread group is destroyed. 
  182.      *
  183.      * @param      daemon   if <code>true</code>, marks this thread group as
  184.      *                      a daemon thread group; otherwise, marks this
  185.      *                      thread group as normal.
  186.      * @exception  SecurityException  if the current thread cannot modify
  187.      *               this thread.
  188.      * @see        java.lang.SecurityException
  189.      * @see        java.lang.ThreadGroup#checkAccess()
  190.      * @since      JDK1.0
  191.      */
  192.     public final void setDaemon(boolean daemon) {
  193.     checkAccess();
  194.     this.daemon = daemon;
  195.     }
  196.  
  197.     /**
  198.      * Sets the maximum priority of the 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.      * Threads in the thread group that already have a higher priority 
  204.      * are not affected. 
  205.      *
  206.      * @param      pri   the new priority of the thread group.
  207.      * @exception  SecurityException  if the current thread cannot modify
  208.      *               this thread group.
  209.      * @see        java.lang.SecurityException
  210.      * @see        java.lang.ThreadGroup#checkAccess()
  211.      * @since      JDK1.0
  212.      */
  213.     public final void setMaxPriority(int pri) {
  214.     int ngroupsSnapshot;
  215.     ThreadGroup[] groupsSnapshot;
  216.     synchronized (this) {
  217.         checkAccess();
  218.         if (pri < Thread.MIN_PRIORITY) {
  219.         maxPriority = Thread.MIN_PRIORITY;
  220.         } else if (pri < maxPriority) {
  221.         maxPriority = pri;
  222.         }
  223.         ngroupsSnapshot = ngroups;
  224.         if (groups != null) {
  225.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  226.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  227.         } else {
  228.         groupsSnapshot = null;
  229.         }
  230.     }
  231.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  232.         groupsSnapshot[i].setMaxPriority(pri);
  233.     }
  234.     }
  235.  
  236.     /**
  237.      * Tests if this thread group is either the thread group 
  238.      * argument or one of its ancestor thread groups. 
  239.      *
  240.      * @param   g   a thread group.
  241.      * @return  <code>true</code> if this thread group is the thread group
  242.      *          argument or one of its ancestor thread groups;
  243.      *          <code>false</code> otherwise.
  244.      * @since   JDK1.0
  245.      */
  246.     public final boolean parentOf(ThreadGroup g) {
  247.     for (; g != null ; g = g.parent) {
  248.         if (g == this) {
  249.         return true;
  250.         }
  251.     }
  252.     return false;
  253.     }
  254.  
  255.     /**
  256.      * Determines if the currently running thread has permission to 
  257.      * modify this thread group. 
  258.      * <p>
  259.      * If there is a security manager, its <code>checkAccess</code> method 
  260.      * is called with this thread group as its argument. This may result 
  261.      * in throwing a <code>SecurityException</code>. 
  262.      *
  263.      * @exception  SecurityException  if the current thread is not allowed to
  264.      *               access this thread group.
  265.      * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
  266.      * @since      JDK1.0
  267.      */
  268.     public final void checkAccess() {
  269.     SecurityManager security = System.getSecurityManager();
  270.     if (security != null) {
  271.         security.checkAccess(this);
  272.     }
  273.     }
  274.  
  275.     /**
  276.      * Returns an estimate of the number of active threads in this
  277.      * thread group.
  278.      *
  279.      * @return  the number of active threads in this thread group and in any
  280.      *          other thread group that has this thread group as an ancestor.
  281.      * @since   JDK1.0
  282.      */
  283.     public int activeCount() {
  284.     int result;
  285.     // Snapshot sub-group data so we don't hold this lock
  286.     // while our children are computing.
  287.     int ngroupsSnapshot;
  288.     ThreadGroup[] groupsSnapshot;
  289.     synchronized (this) {
  290.         if (destroyed) {
  291.         return 0;
  292.         }
  293.         result = nthreads;
  294.         ngroupsSnapshot = ngroups;
  295.         if (groups != null) {
  296.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  297.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  298.         } else {
  299.         groupsSnapshot = null;
  300.         }
  301.     }
  302.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  303.         result += groupsSnapshot[i].activeCount();
  304.     }
  305.     return result;
  306.     }
  307.  
  308.     /**
  309.      * Copies into the specified array every active thread in this 
  310.      * thread group and its subgroups. 
  311.      * <p>
  312.      * An application should use the <code>activeCount</code> method to 
  313.      * get an estimate of how big the array should be. If the array is 
  314.      * too short to hold all the threads, the extra threads are silently 
  315.      * ignored. 
  316.      *
  317.      * @param   list   an array into which to place the list of threads.
  318.      * @return  the number of threads put into the array.
  319.      * @see     java.lang.ThreadGroup#activeCount()
  320.      * @since   JDK1.0
  321.      */
  322.     public int enumerate(Thread list[]) {
  323.     return enumerate(list, 0, true);
  324.     }
  325.  
  326.     /**
  327.      * Copies into the specified array every active thread in this 
  328.      * thread group. If the <code>recurse</code> flag is 
  329.      * <code>true</code>, references to every active thread in this 
  330.      * thread's subgroups are also included. If the array is too short to 
  331.      * hold all the threads, the extra threads are silently ignored. 
  332.      * <p>
  333.      * An application should use the <code>activeCount</code> method to 
  334.      * get an estimate of how big the array should be. 
  335.      *
  336.      * @param   list      an array into which to place the list of threads.
  337.      * @param   recurse   a flag indicating whether also to include threads
  338.      *                    in thread groups that are subgroups of this
  339.      *                    thread group.
  340.      * @return  the number of threads placed into the array.
  341.      * @see     java.lang.ThreadGroup#activeCount()
  342.      * @since   JDK1.0
  343.      */
  344.     public int enumerate(Thread list[], boolean recurse) {
  345.     return enumerate(list, 0, recurse);
  346.     }
  347.  
  348.     private int enumerate(Thread list[], int n, boolean recurse) {
  349.     int ngroupsSnapshot = 0;
  350.     ThreadGroup[] groupsSnapshot = null;
  351.     synchronized (this) {
  352.         if (destroyed) {
  353.         return 0;
  354.         }
  355.         int nt = nthreads;
  356.         if (nt > list.length - n) {
  357.         nt = list.length - n;
  358.         }
  359.         if (nt > 0) {
  360.         System.arraycopy(threads, 0, list, n, nt);
  361.         n += nt;
  362.         }
  363.         if (recurse) {
  364.         ngroupsSnapshot = ngroups;
  365.         if (groups != null) {
  366.             groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  367.             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  368.         } else {
  369.             groupsSnapshot = null;
  370.         }
  371.         }
  372.     }
  373.     if (recurse) {
  374.         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  375.         n = groupsSnapshot[i].enumerate(list, n, true);
  376.         }
  377.     }
  378.     return n;
  379.     }
  380.  
  381.     /**
  382.      * Returns an estimate of the number of active groups in this
  383.      * thread group.
  384.      *
  385.      * @return  the number of active thread groups with this thread group as
  386.      *          an ancestor.
  387.      * @since   JDK1.0
  388.      */
  389.     public int activeGroupCount() {
  390.     int ngroupsSnapshot;
  391.     ThreadGroup[] groupsSnapshot;
  392.     synchronized (this) {
  393.         if (destroyed) {
  394.         return 0;
  395.         }
  396.         ngroupsSnapshot = ngroups;
  397.         if (groups != null) {
  398.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  399.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  400.         } else {
  401.         groupsSnapshot = null;
  402.         }
  403.     }
  404.     int n = ngroupsSnapshot;
  405.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  406.         n += groupsSnapshot[i].activeGroupCount();
  407.     }
  408.     return n;
  409.     }
  410.  
  411.     /**
  412.      * Copies into the specified array references to every active 
  413.      * subgroup in this thread group. 
  414.      * <p>
  415.      * An application should use the <code>activeGroupCount</code> 
  416.      * method to get an estimate of how big the array should be. If the 
  417.      * array is too short to hold all the thread groups, the extra thread 
  418.      * groups are silently ignored. 
  419.      *
  420.      * @param   list   an array into which to place the list of thread groups.
  421.      * @return  the number of thread groups put into the array.
  422.      * @see     java.lang.ThreadGroup#activeGroupCount()
  423.      * @since   JDK1.0
  424.      */
  425.     public int enumerate(ThreadGroup list[]) {
  426.     return enumerate(list, 0, true);
  427.     }
  428.  
  429.     /**
  430.      * Copies into the specified array references to every active 
  431.      * subgroup in this thread group. If the <code>recurse</code> flag is 
  432.      * <code>true</code>, references to all active subgroups of the 
  433.      * subgroups and so forth are also included. 
  434.      * <p>
  435.      * An application should use the <code>activeGroupCount</code> 
  436.      * method to get an estimate of how big the array should be. 
  437.      *
  438.      * @param   list      an array into which to place the list of threads.
  439.      * @param   recurse   a flag indicating whether to recursively enumerate
  440.      *                    all included thread groups.
  441.      * @return  the number of thread groups put into the array.
  442.      * @see     java.lang.ThreadGroup#activeGroupCount()
  443.      * @since   JDK1.0
  444.      */
  445.     public int enumerate(ThreadGroup list[], boolean recurse) {
  446.     return enumerate(list, 0, recurse);
  447.     }
  448.  
  449.     private int enumerate(ThreadGroup list[], int n, boolean recurse) {
  450.     int ngroupsSnapshot = 0;
  451.     ThreadGroup[] groupsSnapshot = null;
  452.     synchronized (this) {
  453.         if (destroyed) {
  454.         return 0;
  455.         }
  456.         int ng = ngroups;
  457.         if (ng > list.length - n) {
  458.         ng = list.length - n;
  459.         }
  460.         if (ng > 0) {
  461.         System.arraycopy(groups, 0, list, n, ng);
  462.         n += ng;
  463.         }
  464.         if (recurse) {
  465.         ngroupsSnapshot = ngroups;
  466.         if (groups != null) {
  467.             groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  468.             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  469.         } else {
  470.             groupsSnapshot = null;
  471.         }
  472.         }
  473.     }
  474.     if (recurse) {
  475.         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  476.         n = groupsSnapshot[i].enumerate(list, n, true);
  477.         }
  478.     }
  479.     return n;
  480.     }
  481.  
  482.     /**
  483.      * Stops all processes in this thread group. 
  484.      * <p>
  485.      * First, the <code>checkAccess</code> method of this thread group is 
  486.      * called with no arguments; this may result in a security exception. 
  487.      * <p>
  488.      * This method then calls the <code>stop</code> method on all the 
  489.      * threads in this thread group and in all of its subgroups. 
  490.      *
  491.      * @exception  SecurityException  if the current thread is not allowed
  492.      *               to access this thread group or any of the threads in
  493.      *               the thread group.
  494.      * @see        java.lang.SecurityException
  495.      * @see        java.lang.Thread#stop()
  496.      * @see        java.lang.ThreadGroup#checkAccess()
  497.      * @since      JDK1.0
  498.      */
  499.     public final void stop() {
  500.     int ngroupsSnapshot;
  501.     ThreadGroup[] groupsSnapshot;
  502.     synchronized (this) {
  503.         checkAccess();
  504.         for (int i = 0 ; i < nthreads ; i++) {
  505.         threads[i].stop();
  506.         }
  507.         ngroupsSnapshot = ngroups;
  508.         if (groups != null) {
  509.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  510.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  511.         } else {
  512.         groupsSnapshot = null;
  513.         }
  514.     }
  515.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  516.         groupsSnapshot[i].stop();
  517.     }
  518.     }
  519.  
  520.     /**
  521.      * Suspends all processes in this thread group. 
  522.      * <p>
  523.      * First, the <code>checkAccess</code> method of this thread group is 
  524.      * called with no arguments; this may result in a security exception. 
  525.      * <p>
  526.      * This method then calls the <code>suspend</code> method on all the 
  527.      * threads in this thread group and in all of its subgroups. 
  528.      *
  529.      * @exception  SecurityException  if the current thread is not allowed
  530.      *               to access this thread group or any of the threads in
  531.      *               the thread group.
  532.      * @see        java.lang.SecurityException
  533.      * @see        java.lang.Thread#suspend()
  534.      * @see        java.lang.ThreadGroup#checkAccess()
  535.      * @since      JDK1.0
  536.      */
  537.     public final void suspend() {
  538.     int ngroupsSnapshot;
  539.     ThreadGroup[] groupsSnapshot;
  540.     synchronized (this) {
  541.         checkAccess();
  542.         for (int i = 0 ; i < nthreads ; i++) {
  543.         threads[i].suspend();
  544.         }
  545.         ngroupsSnapshot = ngroups;
  546.         if (groups != null) {
  547.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  548.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  549.         } else {
  550.         groupsSnapshot = null;
  551.         }
  552.     }
  553.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  554.         groupsSnapshot[i].suspend();
  555.     }
  556.     }
  557.  
  558.     /**
  559.      * Resumes all processes in this thread group. 
  560.      * <p>
  561.      * First, the <code>checkAccess</code> method of this thread group is 
  562.      * called with no arguments; this may result in a security exception. 
  563.      * <p>
  564.      * This method then calls the <code>resume</code> method on all the 
  565.      * threads in this thread group and in all of its sub groups. 
  566.      *
  567.      * @exception  SecurityException  if the current thread is not allowed to
  568.      *               access this thread group or any of the threads in the
  569.      *               thread group.
  570.      * @see        java.lang.SecurityException
  571.      * @see        java.lang.Thread#resume()
  572.      * @see        java.lang.ThreadGroup#checkAccess()
  573.      * @since      JDK1.0
  574.      */
  575.     public final void resume() {
  576.     int ngroupsSnapshot;
  577.     ThreadGroup[] groupsSnapshot;
  578.     synchronized (this) {
  579.         checkAccess();
  580.         for (int i = 0 ; i < nthreads ; i++) {
  581.         threads[i].resume();
  582.         }
  583.         ngroupsSnapshot = ngroups;
  584.         if (groups != null) {
  585.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  586.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  587.         } else {
  588.         groupsSnapshot = null;
  589.         }
  590.     }
  591.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  592.         groupsSnapshot[i].resume();
  593.     }
  594.     }
  595.  
  596.     /**
  597.      * Destroys this thread group and all of its subgroups. This thread 
  598.      * group must be empty, indicating that all threads that had been in 
  599.      * this thread group have since stopped. 
  600.      *
  601.      * @exception  IllegalThreadStateException  if the thread group is not
  602.      *               empty or if the thread group has already been destroyed.
  603.      * @exception  SecurityException  if the current thread cannot modify this
  604.      *               thread group.
  605.      * @since      JDK1.0
  606.      */
  607.     public final void destroy() {
  608.     int ngroupsSnapshot;
  609.     ThreadGroup[] groupsSnapshot;
  610.     synchronized (this) {
  611.         checkAccess();
  612.         if (destroyed || (nthreads > 0)) {
  613.         throw new IllegalThreadStateException();
  614.         }
  615.         ngroupsSnapshot = ngroups;
  616.         if (groups != null) {
  617.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  618.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  619.         } else {
  620.         groupsSnapshot = null;
  621.         }
  622.         if (parent != null) {
  623.         destroyed = true;
  624.         ngroups = 0;
  625.         groups = null;
  626.         nthreads = 0;
  627.         threads = null;
  628.         }
  629.     }
  630.     for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
  631.         groupsSnapshot[i].destroy();
  632.     }
  633.     if (parent != null) {
  634.         parent.remove(this);
  635.     }
  636.     }
  637.  
  638.     /**
  639.      * Adds the specified Thread group to this group.
  640.      * @param g the specified Thread group to be added
  641.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  642.      */
  643.     private final void add(ThreadGroup g){
  644.     synchronized (this) {
  645.         if (destroyed) {
  646.         throw new IllegalThreadStateException();
  647.         }
  648.         if (groups == null) {
  649.         groups = new ThreadGroup[4];
  650.         } else if (ngroups == groups.length) {
  651.         ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
  652.         System.arraycopy(groups, 0, newgroups, 0, ngroups);
  653.         groups = newgroups;
  654.         }
  655.         groups[ngroups] = g;
  656.  
  657.         // This is done last so it doesn't matter in case the
  658.         // thread is killed
  659.         ngroups++;
  660.     }
  661.     }
  662.  
  663.     /**
  664.      * Removes the specified Thread group from this group.
  665.      * @param g the Thread group to be removed
  666.      * @return if this Thread has already been destroyed.
  667.      */
  668.     private void remove(ThreadGroup g) {
  669.     synchronized (this) {
  670.         if (destroyed) {
  671.         return;
  672.         }
  673.         for (int i = 0 ; i < ngroups ; i++) {
  674.         if (groups[i] == g) {
  675.             ngroups -= 1;
  676.             System.arraycopy(groups, i + 1, groups, i, ngroups - i);
  677.             // Zap dangling reference to the dead group so that
  678.             // the garbage collector will collect it.
  679.             groups[ngroups] = null;
  680.             break;
  681.         }
  682.         }
  683.         if (nthreads == 0) {
  684.         notifyAll();
  685.         }
  686.         if (daemon && (nthreads == 0) && (ngroups == 0)) {
  687.         destroy();
  688.         }
  689.     }
  690.     }
  691.     
  692.     /**
  693.      * Adds the specified Thread to this group.
  694.      * @param t the Thread to be added
  695.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  696.      */
  697.     void add(Thread t) {
  698.     synchronized (this) {
  699.         if (destroyed) {
  700.         throw new IllegalThreadStateException();
  701.         }
  702.         if (threads == null) {
  703.         threads = new Thread[4];
  704.         } else if (nthreads == threads.length) {
  705.         Thread newthreads[] = new Thread[nthreads * 2];
  706.         System.arraycopy(threads, 0, newthreads, 0, nthreads);
  707.         threads = newthreads;
  708.         }
  709.         threads[nthreads] = t;
  710.  
  711.         // This is done last so it doesn't matter in case the
  712.         // thread is killed
  713.         nthreads++;
  714.     }
  715.     }
  716.  
  717.     /**
  718.      * Removes the specified Thread from this group.
  719.      * @param t the Thread to be removed
  720.      * @return if the Thread has already been destroyed.
  721.      */
  722.     void remove(Thread t) {
  723.     synchronized (this) {
  724.         if (destroyed) {
  725.         return;
  726.         }
  727.         for (int i = 0 ; i < nthreads ; i++) {
  728.         if (threads[i] == t) {
  729.             System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
  730.             // Zap dangling reference to the dead thread so that
  731.             // the garbage collector will collect it.
  732.             threads[nthreads] = null;
  733.             break;
  734.         }
  735.         }
  736.         if (nthreads == 0) {
  737.         notifyAll();
  738.         }
  739.         if (daemon && (nthreads == 0) && (ngroups == 0)) {
  740.         destroy();
  741.         }
  742.     }
  743.     }
  744.  
  745.     /**
  746.      * Prints information about this thread group to the standard 
  747.      * output. This method is useful only for debugging. 
  748.      *
  749.      * @since   JDK1.0
  750.      */
  751.     public void list() {
  752.     list(System.out, 0);
  753.     }
  754.     void list(PrintStream out, int indent) {
  755.     int ngroupsSnapshot;
  756.     ThreadGroup[] groupsSnapshot;
  757.     synchronized (this) {
  758.         for (int j = 0 ; j < indent ; j++) {
  759.         out.print(" ");
  760.         }
  761.         out.println(this);
  762.         indent += 4;
  763.         for (int i = 0 ; i < nthreads ; i++) {
  764.         for (int j = 0 ; j < indent ; j++) {
  765.             out.print(" ");
  766.         }
  767.         out.println(threads[i]);
  768.         }
  769.         ngroupsSnapshot = ngroups;
  770.         if (groups != null) {
  771.         groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  772.         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  773.         } else {
  774.         groupsSnapshot = null;
  775.         }
  776.     }
  777.     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  778.         groupsSnapshot[i].list(out, indent);
  779.     }
  780.     }
  781.  
  782.     /**
  783.      * Called by the Java Virtual Machine when a thread in this 
  784.      * thread group stops because of an uncaught exception. 
  785.      * <p>
  786.      * The <code>uncaughtException</code> method of 
  787.      * <code>ThreadGroup</code> does the following: 
  788.      * <ul>
  789.      * <li>If this thread group has a parent thread group, the
  790.      *     <code>uncaughtException</code> method of that parent is called
  791.      *     with the same two arguments. 
  792.      * <li>Otherwise, this method determines if the <code>Throwable</code>
  793.      *     argument is an instance of <code>ThreadDeath</code>. If so, nothing
  794.      *     special is done. Otherwise, the <code>Throwable</code>'s
  795.      *     <code>printStackTrace</code> method is called to print a stack
  796.      *     backtrace to the standard error stream.
  797.      * </ul>
  798.      * <p>
  799.      * Applications can override this method in subclasses of 
  800.      * <code>ThreadGroup</code> to provide alternative handling of 
  801.      * uncaught exceptions. 
  802.      *
  803.      * @param   t   the thread that is about to exit.
  804.      * @param   e   the uncaught exception.
  805.      * @see     java.lang.System#err
  806.      * @see     java.lang.ThreadDeath
  807.      * @see     java.lang.Throwable#printStackTrace(java.io.PrintStream)
  808.      * @since   JDK1.0
  809.      */
  810.     public void uncaughtException(Thread t, Throwable e) {
  811.     if (parent != null) {
  812.         parent.uncaughtException(t, e);
  813.     } else if (!(e instanceof ThreadDeath)) {
  814.         e.printStackTrace(System.err);
  815.     }
  816.     }
  817.  
  818.     /**
  819.      * Used by VM to control lowmem implicit suspension.
  820.      *
  821.      * @since   JDK1.1
  822.      */
  823.     public boolean allowThreadSuspension(boolean b) {
  824.     this.vmAllowSuspension = b;
  825.     if (!b) {
  826.         VM.unsuspendSomeThreads();
  827.     }
  828.     return true;
  829.     }
  830.  
  831.     /**
  832.      * Returns a string representation of this Thread group.
  833.      *
  834.      * @return  a string representation of this thread group.
  835.      * @since   JDK1.0
  836.      */
  837.     public String toString() {
  838.     return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
  839.     }
  840. }
  841.