home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 October / Chip_1997-10_cd.bin / tema / sybase / powerj / java.z / ThreadGroup.java < prev    next >
Text File  |  1996-05-03  |  13KB  |  487 lines

  1. /*
  2.  * @(#)ThreadGroup.java    1.23 96/03/25  
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.lang;
  21.  
  22. import java.io.PrintStream;
  23.  
  24. /**
  25.  * A group of Threads. A Thread group can contain a set of Threads
  26.  * as well as a set of other Thread groups. A Thread can access its
  27.  * Thread group, but it can't access the parent of its Thread group.
  28.  * This makes it possible to encapsulate a Thread in a Thread group
  29.  * and stop it from manipulating Threads in the parent group.
  30.  *
  31.  * @version     1.23, 25 Mar 1996
  32.  * @author    Arthur van Hoff
  33.  */
  34. public
  35. class ThreadGroup {
  36.     ThreadGroup parent;
  37.     String name;
  38.     int maxPriority;
  39.     boolean destroyed;
  40.     boolean daemon;
  41.  
  42.     int nthreads;
  43.     Thread threads[];
  44.  
  45.     int ngroups;
  46.     ThreadGroup groups[];
  47.  
  48.     /**
  49.      * Creates an empty Thread group that is not in any Thread group. 
  50.      * This method is used to create the system Thread group.
  51.      */
  52.     private ThreadGroup() {    // called from C code
  53.     this.name = "system";
  54.     this.maxPriority = Thread.MAX_PRIORITY;
  55.     }
  56.  
  57.     /**
  58.      * Creates a new ThreadGroup. Its parent will be the Thread group
  59.      * of the current Thread.
  60.      * @param name the name of the new Thread group created
  61.      */
  62.     public ThreadGroup(String name) {
  63.     this(Thread.currentThread().getThreadGroup(), name);
  64.     }
  65.  
  66.     /**
  67.      * Creates a new ThreadGroup with a specified name in the specified Thread group.
  68.      * @param parent the specified parent Thread group
  69.      * @param name the name of the new Thread group being created
  70.      * @exception NullPointerException If the given thread group is equal to null.
  71.      */
  72.     public ThreadGroup(ThreadGroup parent, String name) {
  73.     if (parent == null) {
  74.         throw new NullPointerException();
  75.     }
  76.     parent.checkAccess();
  77.     this.name = name;
  78.     this.maxPriority = parent.maxPriority;
  79.     this.daemon = parent.daemon;
  80.     this.parent = parent;
  81.     parent.add(this);
  82.     }
  83.  
  84.     /**
  85.      * Gets the name of this Thread group.
  86.      */
  87.     public final String getName() {
  88.     return name;
  89.     }
  90.  
  91.     /**
  92.      * Gets the parent of this Thread group.
  93.      */
  94.     public final ThreadGroup getParent() {
  95.     return parent;
  96.     }
  97.  
  98.     /**
  99.      * Gets the maximum priority of the group. Threads that are
  100.      * part of this group cannot have a higher priority than the maximum priority.
  101.      */
  102.     public final int getMaxPriority() {
  103.     return maxPriority;
  104.     }
  105.  
  106.     /**
  107.      * Returns the daemon flag of the Thread group. A daemon Thread group
  108.      * is automatically destroyed when it is found empty after a Thread
  109.      * group or Thread is removed from it.
  110.      */
  111.     public final boolean isDaemon() {
  112.     return daemon;
  113.     }
  114.  
  115.     /**
  116.      * Changes the daemon status of this group.
  117.      * @param daemon the daemon boolean which is to be set.
  118.      */
  119.     public final void setDaemon(boolean daemon) {
  120.     checkAccess();
  121.     this.daemon = daemon;
  122.     }
  123.  
  124.     /**
  125.      * Sets the maximum priority of the group. Threads
  126.      * that are already in the group <b>can</b> have a higher priority than the
  127.      * set maximum.
  128.      * @param pri the priority of the Thread group
  129.      */
  130.     public final synchronized void setMaxPriority(int pri) {
  131.     checkAccess();
  132.     if (pri < Thread.MIN_PRIORITY) {
  133.         maxPriority = Thread.MIN_PRIORITY;
  134.     } else if (pri < maxPriority) {
  135.         maxPriority = pri;
  136.     }
  137.     for (int i = 0 ; i < ngroups ; i++) {
  138.         groups[i].setMaxPriority(pri);
  139.     }
  140.     }
  141.  
  142.     /**
  143.      * Checks to see if this Thread group is a parent of or is equal to
  144.      * another Thread group.
  145.      * @param g the Thread group to be checked
  146.      * @return true if this Thread group is equal to or is the parent of another Thread
  147.      * group; false otherwise.
  148.      */
  149.     public final boolean parentOf(ThreadGroup g) {
  150.     for (; g != null ; g = g.parent) {
  151.         if (g == this) {
  152.         return true;
  153.         }
  154.     }
  155.     return false;
  156.     }
  157.  
  158.     /**
  159.      * Checks to see if the current Thread is allowed to modify this group.
  160.      * @exception SecurityException If the current Thread is not allowed 
  161.      * to access this Thread group.
  162.      */
  163.     public final void checkAccess() {
  164.     SecurityManager security = System.getSecurityManager();
  165.     if (security != null) {
  166.         security.checkAccess(this);
  167.     }
  168.     }
  169.  
  170.     /**
  171.      * Returns an estimate of the number of active Threads in the
  172.      * Thread group.
  173.      */
  174.     public synchronized int activeCount() {
  175.     if (destroyed) {
  176.             return 0;
  177.     }
  178.     int n = nthreads;
  179.     for (int i = 0 ; i < ngroups ; i++) {
  180.         n += groups[i].activeCount();
  181.     }
  182.     return n;
  183.     }
  184.  
  185.     /**
  186.      * Copies, into the specified array, references to every active Thread in this Thread group.
  187.      * You can use the activeCount() method to get an estimate of how big
  188.      * the array should be.
  189.      * @param list an array of Threads
  190.      * @return the number of Threads put into the array
  191.      */
  192.     public int enumerate(Thread list[]) {
  193.     return enumerate(list, 0, true);
  194.     }
  195.  
  196.     /**
  197.      * Copies, into the specified array, references to every active Thread in this Thread group.
  198.      * You can use the activeCount() method to get an estimate of how big
  199.      * the array should be.
  200.      * @param list an array list of Threads
  201.      * @param recurse a boolean indicating whether a Thread has reapearred
  202.      * @return the number of Threads placed into the array.
  203.      */
  204.     public int enumerate(Thread list[], boolean recurse) {
  205.     return enumerate(list, 0, recurse);
  206.     }
  207.  
  208.     private synchronized int enumerate(Thread list[], int n, boolean recurse) {
  209.     if (destroyed) {
  210.             return 0;
  211.     }
  212.     int nt = nthreads;
  213.     if (nt > list.length - n) {
  214.         nt = list.length - n;
  215.     }
  216.     if (nt > 0) {
  217.         System.arraycopy(threads, 0, list, n, nt);
  218.         n += nt;
  219.     }
  220.     if (recurse) {
  221.         for (int i = 0 ; i < ngroups ; i++) {
  222.         n = groups[i].enumerate(list, n, true);
  223.         }
  224.     }
  225.     return n;
  226.     }
  227.  
  228.     /**
  229.      * Returns an estimate of the number of active groups in the
  230.      * Thread group.
  231.      */
  232.     public synchronized int activeGroupCount() {
  233.     if (destroyed) {
  234.             return 0;
  235.     }
  236.     int n = ngroups;
  237.     for (int i = 0 ; i < ngroups ; i++) {
  238.         n += groups[i].activeGroupCount();
  239.     }
  240.     return n;
  241.     }
  242.  
  243.     /**
  244.      * Copies, into the specified array, references to every active Thread group in this Thread 
  245.      * group.  You can use the activeGroupCount() method to get an estimate of how big
  246.      * the array should be.
  247.      * @param list an array of Thread groups
  248.      * @return the number of Thread groups placed into the array.
  249.      */
  250.     public int enumerate(ThreadGroup list[]) {
  251.     return enumerate(list, 0, true);
  252.     }
  253.  
  254.     /**
  255.      * Copies, into the specified array, references to every active Thread group in this Thread 
  256.      * group.  You can use the activeGroupCount() method to get an estimate of how big
  257.      * the array should be.
  258.      * @param list an array list of Thread groups
  259.      * @param recurse a boolean indicating if a Thread group has reappeared
  260.      * @return the number of Thread groups placed into the array.
  261.      */
  262.     public int enumerate(ThreadGroup list[], boolean recurse) {
  263.     return enumerate(list, 0, recurse);
  264.     }
  265.  
  266.     private synchronized int enumerate(ThreadGroup list[], int n, boolean recurse) {
  267.     if (destroyed) {
  268.             return 0;
  269.     }
  270.     int ng = ngroups;
  271.     if (ng > list.length - n) {
  272.         ng = list.length - n;
  273.     }
  274.     if (ng > 0) {
  275.         System.arraycopy(groups, 0, list, n, ng);
  276.         n += ng;
  277.     }
  278.     if (recurse) {
  279.         for (int i = 0 ; i < ngroups ; i++) {
  280.         n = groups[i].enumerate(list, n, true);
  281.         }
  282.     }
  283.     return n;
  284.     }
  285.  
  286.     /**
  287.      * Stops all the Threads in this Thread group and all of its sub groups.
  288.      */
  289.     public final synchronized void stop() {
  290.     checkAccess();
  291.     for (int i = 0 ; i < ngroups ; i++) {
  292.         groups[i].stop();
  293.     }
  294.     for (int i = 0 ; i < nthreads ; i++) {
  295.         threads[i].stop();
  296.     }
  297.     }
  298.  
  299.     /**
  300.      * Suspends all the Threads in this Thread group and all of its sub groups.
  301.      */
  302.     public final synchronized void suspend() {
  303.     checkAccess();
  304.     for (int i = 0 ; i < ngroups ; i++) {
  305.         groups[i].suspend();
  306.     }
  307.     for (int i = 0 ; i < nthreads ; i++) {
  308.         threads[i].suspend();
  309.     }
  310.     }
  311.  
  312.     /**
  313.      * Resumes all the Threads in this Thread group and all of its sub groups.
  314.      */
  315.     public final synchronized void resume() {
  316.     checkAccess();
  317.     for (int i = 0 ; i < ngroups ; i++) {
  318.         groups[i].resume();
  319.     }
  320.     for (int i = 0 ; i < nthreads ; i++) {
  321.         threads[i].resume();
  322.     }
  323.     }
  324.  
  325.     /**
  326.      * Destroys a Thread group. This does <b>NOT</b> stop the Threads
  327.      * in the Thread group.
  328.      * @exception IllegalThreadStateException If the Thread group is not empty
  329.      *         or if the Thread group was already destroyed.
  330.      */
  331.     public final synchronized void destroy() {
  332.     checkAccess();
  333.     if (destroyed || (nthreads > 0)) {
  334.         throw new IllegalThreadStateException();
  335.     }
  336.     while (ngroups > 0) {
  337.         groups[0].destroy();
  338.     }
  339.     if (parent != null) {
  340.         destroyed = true;
  341.         groups = null;
  342.         threads = null;
  343.         parent.remove(this);
  344.     }
  345.     }
  346.  
  347.     /**
  348.      * Adds the specified Thread group to this group.
  349.      * @param g the specified Thread group to be added
  350.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  351.      */
  352.     private final synchronized void add(ThreadGroup g){
  353.     if (destroyed) {
  354.         throw new IllegalThreadStateException();
  355.     }
  356.     if (groups == null) {
  357.         groups = new ThreadGroup[4];
  358.     } else if (ngroups == groups.length) {
  359.         ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
  360.         System.arraycopy(groups, 0, newgroups, 0, ngroups);
  361.         groups = newgroups;
  362.     }
  363.     groups[ngroups] = g;
  364.  
  365.     // This is done last so it doesn't matter in case the
  366.     // thread is killed
  367.     ngroups++;
  368.     }
  369.  
  370.     /**
  371.      * Removes the specified Thread group from this group.
  372.      * @param g the Thread group to be removed
  373.      * @return if this Thread has already been destroyed.
  374.      */
  375.     private synchronized void remove(ThreadGroup g) {
  376.     if (destroyed) {
  377.         return;
  378.     }
  379.     for (int i = 0 ; i < ngroups ; i++) {
  380.         if (groups[i] == g) {
  381.         System.arraycopy(groups, i + 1, groups, i, --ngroups - i);
  382.         // Zap dangling reference to the dead group so that
  383.         // the garbage collector will collect it.
  384.         groups[ngroups] = null;
  385.         break;
  386.         }
  387.     }
  388.     if (nthreads == 0) {
  389.         notifyAll();
  390.     }
  391.     if (daemon && (nthreads == 0) && (ngroups == 0)) {
  392.         destroy();
  393.     }
  394.     }
  395.     
  396.     /**
  397.      * Adds the specified Thread to this group.
  398.      * @param t the Thread to be added
  399.      * @exception IllegalThreadStateException If the Thread group has been destroyed.
  400.      */
  401.     synchronized void add(Thread t) {
  402.     if (destroyed) {
  403.         throw new IllegalThreadStateException();
  404.     }
  405.     if (threads == null) {
  406.         threads = new Thread[4];
  407.     } else if (nthreads == threads.length) {
  408.         Thread newthreads[] = new Thread[nthreads * 2];
  409.         System.arraycopy(threads, 0, newthreads, 0, nthreads);
  410.         threads = newthreads;
  411.     }
  412.     threads[nthreads] = t;
  413.  
  414.     // This is done last so it doesn't matter in case the
  415.     // thread is killed
  416.     nthreads++;
  417.     }
  418.  
  419.     /**
  420.      * Removes the specified Thread from this group.
  421.      * @param t the Thread to be removed
  422.      * @return if the Thread has already been destroyed.
  423.      */
  424.     synchronized void remove(Thread t) {
  425.     if (destroyed) {
  426.         return;
  427.     }
  428.     for (int i = 0 ; i < nthreads ; i++) {
  429.         if (threads[i] == t) {
  430.         System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
  431.         // Zap dangling reference to the dead thread so that
  432.         // the garbage collector will collect it.
  433.         threads[nthreads] = null;
  434.         break;
  435.         }
  436.     }
  437.     if (nthreads == 0) {
  438.         notifyAll();
  439.     }
  440.     if (daemon && (nthreads == 0) && (ngroups == 0)) {
  441.         destroy();
  442.     }
  443.     }
  444.  
  445.     /**
  446.      * Lists this Thread group. Useful for debugging only.
  447.      */
  448.      public synchronized void list() {
  449.     list(System.out, 0);
  450.      }
  451.      void list(PrintStream out, int indent) {
  452.     for (int j = 0 ; j < indent ; j++) {
  453.         out.print(" ");
  454.     }
  455.     out.println(this);
  456.     indent += 4;
  457.     for (int i = 0 ; i < nthreads ; i++) {
  458.         for (int j = 0 ; j < indent ; j++) {
  459.         out.print(" ");
  460.         }
  461.         out.println(threads[i]);
  462.     }
  463.     for (int i = 0 ; i < ngroups ; i++) {
  464.         groups[i].list(out, indent);
  465.     }
  466.      }
  467.  
  468.     /**
  469.      * Called when a thread in this group exists because of
  470.      * an uncaught exception.
  471.      */
  472.     public void uncaughtException(Thread t, Throwable e) {
  473.     if (parent != null) {
  474.         parent.uncaughtException(t, e);
  475.     } else if (!(e instanceof ThreadDeath)) {
  476.         e.printStackTrace(System.err);
  477.     }
  478.     }
  479.  
  480.     /**
  481.      * Returns a String representation of the Thread group.
  482.      */
  483.     public String toString() {
  484.     return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
  485.     }
  486. }
  487.