home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / lang / ThreadGroup.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  27.1 KB  |  882 lines

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