/[classpath]/classpath/java/lang/ThreadGroup.java
ViewVC logotype

Diff of /classpath/java/lang/ThreadGroup.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.10 by mark, Tue Jan 22 22:27:00 2002 UTC revision 1.11 by ericb, Wed Mar 20 20:04:32 2002 UTC
# Line 1  Line 1 
1  /* java.lang.ThreadGroup  /* ThreadGroup -- a group of Threads
2     Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.     Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
5    
# Line 7  GNU Classpath is free software; you can Line 7  GNU Classpath is free software; you can
7  it under the terms of the GNU General Public License as published by  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2, or (at your option)  the Free Software Foundation; either version 2, or (at your option)
9  any later version.  any later version.
10    
11  GNU Classpath is distributed in the hope that it will be useful, but  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Line 34  or based on this library.  If you modify Line 34  or based on this library.  If you modify
34  this exception to your version of the library, but you are not  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */  exception statement from your version. */
37    
38  package java.lang;  package java.lang;
39    
40  import java.util.Vector;  import java.util.Vector;
 import java.util.Enumeration;  
41    
 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3  
  * "The Java Language Specification", ISBN 0-201-63451-1  
  * plus online API docs for JDK 1.2 from http://www.javasoft.com.  
  * Status:  Complete for 1.2.  Some parts from the JDK 1.0 spec only are  
  * not implemented.  
  */  
   
42  /**  /**
43   * ThreadGroup allows you to group Threads together.  There is a   * ThreadGroup allows you to group Threads together.  There is a hierarchy
44   * hierarchy of ThreadGroups, and only the initial ThreadGroup has   * of ThreadGroups, and only the initial ThreadGroup has no parent.  A Thread
45   * no parent.  A Thread may access information about its own   * may access information about its own ThreadGroup, but not its parents or
46   * ThreadGroup, but not its parents or others outside the tree.   * others outside the tree.
47   *   *
48   * @author John Keiser   * @author John Keiser
49   * @author Tom Tromey   * @author Tom Tromey
50   * @author Bryce McKinlay   * @author Bryce McKinlay
51   * @version 1.2.0   * @author Eric Blake <ebb9@email.byu.edu>
52   * @since JDK1.0   * @see Thread
53     * @since 1.0
54     * @status updated to 1.4
55   */   */
   
56  public class ThreadGroup  public class ThreadGroup
57  {  {
58    /* The Initial, top-level ThreadGroup. */    /** The Initial, top-level ThreadGroup. */
59    static ThreadGroup root = new ThreadGroup();    static ThreadGroup root = new ThreadGroup();
60    /* This flag is set if an uncaught exception occurs. The runtime should  
61    check this and exit with an error status if it is set. */    /**
62    static boolean had_uncaught_exception = false;     * This flag is set if an uncaught exception occurs. The runtime should
63       * check this and exit with an error status if it is set.
64    private ThreadGroup parent;     */
65    private String name;    static boolean had_uncaught_exception;
66    private Vector threads = new Vector();  
67      /** The parent thread group. */
68      private final ThreadGroup parent;
69    
70      /** The group name, non-null. */
71      final String name;
72    
73      /** The threads in the group. */
74      private final Vector threads = new Vector();
75    
76      /** Child thread groups, or null when this group is destroyed. */
77    private Vector groups = new Vector();    private Vector groups = new Vector();
78    
79      /** If all threads in the group are daemons. */
80    private boolean daemon_flag = false;    private boolean daemon_flag = false;
   private int maxpri = Thread.MAX_PRIORITY;  
81    
82      /** The maximum group priority. */
83      private int maxpri;
84    
85      /**
86       * Hidden constructor to build the root node.
87       */
88    private ThreadGroup()    private ThreadGroup()
89    {    {
90      name = "main";          name = "main";
91        parent = null;
92        maxpri = Thread.MAX_PRIORITY;
93    }    }
94    
95    /** Create a new ThreadGroup using the given name and the    /**
96     *  current thread's ThreadGroup as a parent.     * Create a new ThreadGroup using the given name and the current thread's
97     *  @param name the name to use for the ThreadGroup.     * ThreadGroup as a parent. There may be a security check,
98       * <code>checkAccess</code>.
99       *
100       * @param name the name to use for the ThreadGroup
101       * @throws SecurityException if the current thread cannot create a group
102       * @see #checkAccess()
103     */     */
104    public ThreadGroup(String name)    public ThreadGroup(String name)
105    {    {
106      this (Thread.currentThread().getThreadGroup(), name);      this(Thread.currentThread().group, name);
107    }    }
108    
109    /** Create a new ThreadGroup using the given name and    /**
110     *  parent group.     * Create a new ThreadGroup using the given name and parent group. The new
111     *  @param name the name to use for the ThreadGroup.     * group inherits the maximum priority and daemon status of its parent
112     *  @param parent the ThreadGroup to use as a parent.     * group. There may be a security check, <code>checkAccess</code>.
113     *  @exception NullPointerException if parent is null.     *
114     *  @exception SecurityException if you cannot change     * @param name the name to use for the ThreadGroup
115     *             the intended parent group.     * @param parent the ThreadGroup to use as a parent
116       * @throws NullPointerException if parent is null
117       * @throws SecurityException if the current thread cannot create a group
118       * @throws IllegalThreadStateException if the parent is destroyed
119       * @see #checkAccess()
120     */     */
121    public ThreadGroup(ThreadGroup parent, String name)    public ThreadGroup(ThreadGroup parent, String name)
122    {    {
123      parent.checkAccess();      parent.checkAccess();
124      this.parent = parent;      this.parent = parent;
     if (parent.isDestroyed())  
       throw new IllegalArgumentException ();  
125      this.name = name;      this.name = name;
126      maxpri = parent.maxpri;      maxpri = parent.maxpri;
127      daemon_flag = parent.daemon_flag;      daemon_flag = parent.daemon_flag;
128      parent.addGroup(this);      synchronized (parent)
129          {
130            if (parent.groups == null)
131              throw new IllegalThreadStateException();
132            parent.groups.add(this);
133          }
134    }    }
135    
136    /** Get the name of this ThreadGroup.    /**
137     *  @return the name of this ThreadGroup.     * Get the name of this ThreadGroup.
138       *
139       * @return the name of this ThreadGroup
140     */     */
141    public final String getName()    public final String getName()
142    {    {
143      return name;      return name;
144    }    }
145    
146    /** Get the parent of this ThreadGroup.    /**
147     *  @return the parent of this ThreadGroup.     * Get the parent of this ThreadGroup. If the parent is not null, there
148       * may be a security check, <code>checkAccess</code>.
149       *
150       * @return the parent of this ThreadGroup
151       * @throws SecurityException if permission is denied
152     */     */
153    public final ThreadGroup getParent()    public final ThreadGroup getParent()
154    {    {
155        if (parent != null)
156          parent.checkAccess();
157      return parent;      return parent;
158    }    }
159    
160    /** Set the maximum priority for Threads in this ThreadGroup. setMaxPriority    /**
161     *  can only be used to reduce the current maximum. If maxpri     * Get the maximum priority of Threads in this ThreadGroup. Threads created
162     *  is greater than the current Maximum, the current value is not changed.     * after this call in this group may not exceed this priority.
163     *  Calling this does not effect threads already in this ThreadGroup.     *
164     *  @param maxpri the new maximum priority for this ThreadGroup.     * @return the maximum priority of Threads in this ThreadGroup
    *  @exception SecurityException if you cannoy modify this ThreadGroup.  
    */  
   public final synchronized void setMaxPriority(int maxpri)  
   {  
     checkAccess();  
     if (maxpri < this.maxpri  
         && maxpri >= Thread.MIN_PRIORITY  
         && maxpri <= Thread.MAX_PRIORITY)  
       {  
         this.maxpri = maxpri;          
       }    
   }  
   
   /** Get the maximum priority of Threads in this ThreadGroup.  
    *  @return the maximum priority of Threads in this ThreadGroup.  
165     */     */
166    public final int getMaxPriority()    public final int getMaxPriority()
167    {    {
168      return maxpri;      return maxpri;
169    }    }
170    
171    /** Set whether this ThreadGroup is a daemon group.  A daemon    /**
172     *  group will be destroyed when its last thread is stopped and     * Tell whether this ThreadGroup is a daemon group.  A daemon group will
173     *  its last thread group is destroyed.     * be automatically destroyed when its last thread is stopped and
174     *  @specnote The Java API docs indicate that the group is destroyed     * its last thread group is destroyed.
175     *            when either of those happen, but that doesn't make     *
176     *            sense.     * @return whether this ThreadGroup is a daemon group
    *  @param daemon whether this ThreadGroup should be a daemon group.  
    *  @exception SecurityException if you cannoy modify this ThreadGroup.  
177     */     */
   public final void setDaemon (boolean daemon)  
   {  
     checkAccess();  
     daemon_flag = daemon;  
   }  
     
   /** Tell whether this ThreadGroup is a daemon group.  A daemon  
     * group will be destroyed when its last thread is stopped and  
     * its last thread group is destroyed.  
     * @specnote The Java API docs indicate that the group is destroyed  
     *           when either of those happen, but that doesn't make  
     *           sense.  
     * @return whether this ThreadGroup is a daemon group.  
     */  
178    public final boolean isDaemon()    public final boolean isDaemon()
179    {    {
180      return daemon_flag;      return daemon_flag;
181    }    }
182    
183    /** Tell whether this ThreadGroup has been destroyed or not.    /**
184      * @return whether this ThreadGroup has been destroyed or not.     * Tell whether this ThreadGroup has been destroyed or not.
185      */     *
186       * @return whether this ThreadGroup has been destroyed or not
187       * @since 1.1
188       */
189    public synchronized boolean isDestroyed()    public synchronized boolean isDestroyed()
190    {    {
191      return parent == null && this != root;      return groups == null;
192    }    }
193    
194    /** Check whether this ThreadGroup is an ancestor of the    /**
195      * specified ThreadGroup, or if they are the same.     * Set whether this ThreadGroup is a daemon group.  A daemon group will be
196      *     * destroyed when its last thread is stopped and its last thread group is
197      * @param g the group to test on.     * destroyed. There may be a security check, <code>checkAccess</code>.
198      * @return whether this ThreadGroup is a parent of the     *
199      *         specified group.     * @param daemon whether this ThreadGroup should be a daemon group
200      */     * @throws SecurityException if you cannot modify this ThreadGroup
201       * @see #checkAccess()
202       */
203      public final void setDaemon(boolean daemon)
204      {
205        checkAccess();
206        daemon_flag = daemon;
207      }
208    
209      /**
210       * Set the maximum priority for Threads in this ThreadGroup. setMaxPriority
211       * can only be used to reduce the current maximum. If maxpri is greater
212       * than the current Maximum of the parent group, the current value is not
213       * changed. Otherwise, all groups which belong to this have their priority
214       * adjusted as well. Calling this does not affect threads already in this
215       * ThreadGroup. There may be a security check, <code>checkAccess</code>.
216       *
217       * @param maxpri the new maximum priority for this ThreadGroup
218       * @throws SecurityException if you cannot modify this ThreadGroup
219       * @see #getMaxPriority()
220       * @see #checkAccess()
221       */
222      public final synchronized void setMaxPriority(int maxpri)
223      {
224        checkAccess();
225        if (maxpri < Thread.MIN_PRIORITY || maxpri > Thread.MAX_PRIORITY)
226          return;
227        if (parent != null && maxpri > parent.maxpri)
228          maxpri = parent.maxpri;
229        this.maxpri = maxpri;
230        if (groups == null)
231          return;
232        int i = groups.size();
233        while (--i >= 0)
234          ((ThreadGroup) groups.get(i)).setMaxPriority(maxpri);
235      }
236    
237      /**
238       * Check whether this ThreadGroup is an ancestor of the specified
239       * ThreadGroup, or if they are the same.
240       *
241       * @param g the group to test on
242       * @return whether this ThreadGroup is a parent of the specified group
243       */
244    public final boolean parentOf(ThreadGroup tg)    public final boolean parentOf(ThreadGroup tg)
245    {    {
246      while (tg != null)      while (tg != null)
# Line 205  public class ThreadGroup Line 252  public class ThreadGroup
252      return false;      return false;
253    }    }
254    
255    /** Return the total number of active threads in this ThreadGroup    /**
256      * and all its descendants.<P>     * Find out if the current Thread can modify this ThreadGroup. This passes
257      *     * the check on to <code>SecurityManager.checkAccess(this)</code>.
258      * This cannot return an exact number, since the status of threads     *
259      * may change after they were counted.  But it should be pretty     * @throws SecurityException if the current Thread cannot modify this
260      * close.<P>     *         ThreadGroup
261      *     * @see SecurityManager#checkAccess(ThreadGroup)
262      * @return the number of active threads in this ThreadGroup and     */
263      *         its descendants.    public final void checkAccess()
     * @specnote it isn't clear what the definition of an "Active" thread is.  
     *           Current JDKs regard a thread as active if has been  
     *           started and not finished.  We implement this behaviour.  
     *           There is a JDC bug, <A HREF="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html">  
     *           4089701</A>, regarding this issue.  
     *            
     */  
   public synchronized int activeCount()  
264    {    {
265      int total = 0;      // Bypass System.getSecurityManager, for bootstrap efficiency.
266      for (int i = 0; i < threads.size(); ++i)      SecurityManager sm = Runtime.getSecurityManager();
267        {      if (sm != null)
268          if (((Thread) threads.elementAt(i)).isAlive ())        sm.checkAccess(this);
269            ++total;    }
       }  
270    
271      for (int i=0; i < groups.size(); i++)    /**
272        {     * Return an estimate of the total number of active threads in this
273          ThreadGroup g = (ThreadGroup) groups.elementAt(i);     * ThreadGroup and all its descendants. This cannot return an exact number,
274          total += g.activeCount();     * since the status of threads may change after they were counted; but it
275        }     * should be pretty close. Based on a JDC bug,
276       * <a href="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html">
277       * 4089701</a>, we take active to mean isAlive().
278       *
279       * @return count of active threads in this ThreadGroup and its descendants
280       */
281      public int activeCount()
282      {
283        int total = 0;
284        if (groups == null)
285          return total;
286        int i = threads.size();
287        while (--i >= 0)
288          if (((Thread) threads.get(i)).isAlive())
289            total++;
290        i = groups.size();
291        while (--i >= 0)
292          total += ((ThreadGroup) groups.get(i)).activeCount();
293      return total;      return total;
294    }    }
295    
296    /** Get the number of active groups in this ThreadGroup.  This group    /**
297      * itself is not included in the count.     * Copy all of the active Threads from this ThreadGroup and its descendants
298      * @specnote it is unclear what exactly constitutes an     * into the specified array.  If the array is not big enough to hold all
299      *           active ThreadGroup.  Currently we assume that     * the Threads, extra Threads will simply not be copied. There may be a
300      *           all sub-groups are active, per current JDKs.     * security check, <code>checkAccess</code>.
301      * @return the number of active groups in this ThreadGroup.     *
302      */     * @param array the array to put the threads into
303    public synchronized int activeGroupCount()     * @return the number of threads put into the array
304       * @throws SecurityException if permission was denied
305       * @throws NullPointerException if array is null
306       * @throws ArrayStoreException if a thread does not fit in the array
307       * @see #activeCount()
308       * @see #checkAccess()
309       * @see #enumerate(Thread[], boolean)
310       */
311      public int enumerate(Thread[] array)
312    {    {
313      int total = groups.size();      return enumerate(array, 0, true);
     for (int i=0; i < groups.size(); i++)  
       {  
         ThreadGroup g = (ThreadGroup) groups.elementAt(i);  
         total += g.activeGroupCount();  
       }  
     return total;  
314    }    }
315    
316    /** Copy all of the active Threads from this ThreadGroup and    /**
317      * its descendants into the specified array.  If the array is     * Copy all of the active Threads from this ThreadGroup and, if desired,
318      * not big enough to hold all the Threads, extra Threads will     * from its descendants, into the specified array. If the array is not big
319      * simply not be copied.     * enough to hold all the Threads, extra Threads will simply not be copied.
320      *     * There may be a security check, <code>checkAccess</code>.
321      * @param threads the array to put the threads into.     *
322      * @return the number of threads put into the array.     * @param array the array to put the threads into
323      */     * @param recurse whether to recurse into descendent ThreadGroups
324    public int enumerate(Thread[] threads)     * @return the number of threads put into the array
325    {     * @throws SecurityException if permission was denied
326      return enumerate(threads, 0, true);     * @throws NullPointerException if array is null
327    }     * @throws ArrayStoreException if a thread does not fit in the array
328       * @see #activeCount()
329    /** Copy all of the active Threads from this ThreadGroup and,     * @see #checkAccess()
330      * if desired, from its descendants, into the specified array.     */
331      * If the array is not big enough to hold all the Threads,    public int enumerate(Thread[] array, boolean recurse)
     * extra Threads will simply not be copied.  
     *  
     * @param threads the array to put the threads into.  
     * @param useDescendants whether to count Threads in this  
     *        ThreadGroup's descendants or not.  
     * @return the number of threads put into the array.  
     */  
   public int enumerate(Thread[] threads, boolean useDescendants)  
   {  
     return enumerate(threads, 0, useDescendants);  
   }  
   
   // This actually implements enumerate.  
   private synchronized int enumerate(Thread[] list, int next_index,  
                                      boolean recurse)  
332    {    {
333      Enumeration e = threads.elements();      return enumerate(array, 0, recurse);
     while (e.hasMoreElements() && next_index < list.length)  
       {  
         Thread t = (Thread) e.nextElement();  
         if (t.isAlive ())  
           list[next_index++] = t;  
       }  
     if (recurse && next_index != list.length)  
       {  
         e = groups.elements();  
         while (e.hasMoreElements() && next_index < list.length)  
           {  
             ThreadGroup g = (ThreadGroup) e.nextElement();  
             next_index = g.enumerate(list, next_index, true);  
           }  
       }  
     return next_index;  
334    }    }
335    
336    /** Copy all active ThreadGroups that are descendants of this    /**
337      * ThreadGroup into the specified array.  If the array is not     * Get the number of active groups in this ThreadGroup.  This group itself
338      * large enough to hold all active ThreadGroups, extra     * is not included in the count. A sub-group is active if it has not been
339      * ThreadGroups simply will not be copied.     * destroyed. This cannot return an exact number, since the status of
340      *     * threads may change after they were counted; but it should be pretty close.
341      * @param groups the array to put the ThreadGroups into.     *
342      * @return the number of ThreadGroups copied into the array.     * @return the number of active groups in this ThreadGroup
343      */     */
344    public int enumerate(ThreadGroup[] groups)    public int activeGroupCount()
   {  
     return enumerate(groups, 0, true);  
   }  
   
   /** Copy all active ThreadGroups that are children of this  
     * ThreadGroup into the specified array, and if desired, also  
     * copy all active descendants into the array.  If the array  
     * is not large enough to hold all active ThreadGroups, extra  
     * ThreadGroups simply will not be copied.  
     *  
     * @param groups the array to put the ThreadGroups into.  
     * @param recurse whether to include all descendants  
     *        of this ThreadGroup's children in determining  
     *        activeness.  
     * @return the number of ThreadGroups copied into the array.  
     */  
   public int enumerate(ThreadGroup[] groups, boolean recurse)  
   {  
     return enumerate(groups, 0, recurse);  
   }  
   
   // This actually implements enumerate.  
   private synchronized int enumerate (ThreadGroup[] list, int next_index,  
                                       boolean recurse)  
345    {    {
346      Enumeration e = groups.elements();      if (groups == null)
347      while (e.hasMoreElements() && next_index < list.length)        return 0;
348        {      int total = groups.size();
349          ThreadGroup g = (ThreadGroup) e.nextElement();      int i = total;
350          list[next_index++] = g;      while (--i >= 0)
351          if (recurse && next_index != list.length)        total += ((ThreadGroup) groups.get(i)).activeGroupCount();
352            next_index = g.enumerate(list, next_index, true);      return total;
       }  
     return next_index;  
353    }    }
354    
355    /** Interrupt all Threads in this ThreadGroup and its sub-groups.    /**
356      * @exception SecurityException if you cannot modify this     * Copy all active ThreadGroups that are descendants of this ThreadGroup
357      *            ThreadGroup or any of its Threads or children     * into the specified array.  If the array is not large enough to hold all
358      *            ThreadGroups.     * active ThreadGroups, extra ThreadGroups simply will not be copied. There
359      * @since JDK1.2     * may be a security check, <code>checkAccess</code>.
360      */     *
361    public final synchronized void interrupt()     * @param array the array to put the ThreadGroups into
362       * @return the number of ThreadGroups copied into the array
363       * @throws SecurityException if permission was denied
364       * @throws NullPointerException if array is null
365       * @throws ArrayStoreException if a group does not fit in the array
366       * @see #activeCount()
367       * @see #checkAccess()
368       * @see #enumerate(ThreadGroup[], boolean)
369       */
370      public int enumerate(ThreadGroup[] array)
371    {    {
372      checkAccess();      return enumerate(array, 0, true);
     for (int i=0; i < threads.size(); i++)  
       {  
         Thread t = (Thread) threads.elementAt(i);  
         t.interrupt();  
       }  
     for (int i=0; i < groups.size(); i++)  
       {  
         ThreadGroup tg = (ThreadGroup) groups.elementAt(i);  
         tg.interrupt();  
       }  
373    }    }
374    
375    /** Stop all Threads in this ThreadGroup and its descendants.    /**
376      * @exception SecurityException if you cannot modify this     * Copy all active ThreadGroups that are children of this ThreadGroup into
377      *            ThreadGroup or any of its Threads or children     * the specified array, and if desired, also all descendents.  If the array
378      *            ThreadGroups.     * is not large enough to hold all active ThreadGroups, extra ThreadGroups
379      * @deprecated This method calls Thread.stop(), which is dangerous.     * simply will not be copied. There may be a security check,
380      */     * <code>checkAccess</code>.
381    public final synchronized void stop()     *
382       * @param array the array to put the ThreadGroups into
383       * @param recurse whether to recurse into descendent ThreadGroups
384       * @return the number of ThreadGroups copied into the array
385       * @throws SecurityException if permission was denied
386       * @throws NullPointerException if array is null
387       * @throws ArrayStoreException if a group does not fit in the array
388       * @see #activeCount()
389       * @see #checkAccess()
390       */
391      public int enumerate(ThreadGroup[] array, boolean recurse)
392    {    {
393      checkAccess();      return enumerate(array, 0, recurse);
     for (int i=0; i<threads.size(); i++)  
       {  
         Thread t = (Thread) threads.elementAt(i);  
         t.stop();  
       }  
     for (int i=0; i < groups.size(); i++)  
       {  
         ThreadGroup tg = (ThreadGroup) groups.elementAt(i);  
         tg.stop();  
       }  
394    }    }
395    
396    /** Suspend all Threads in this ThreadGroup and its descendants.    /**
397      * @exception SecurityException if you cannot modify this     * Stop all Threads in this ThreadGroup and its descendants.
398      *            ThreadGroup or any of its Threads or children     *
399      *            ThreadGroups.     * <p>This is inherently unsafe, as it can interrupt synchronized blocks and
400      * @deprecated This method calls Thread.suspend(), which is dangerous.     * leave data in bad states.  Hence, there is a security check:
401      */     * <code>checkAccess()</code>, followed by further checks on each thread
402       * being stopped.
403       *
404       * @throws SecurityException if permission is denied
405       * @see #checkAccess()
406       * @see Thread#stop(Throwable)
407       * @deprecated unsafe operation, try not to use
408       */
409      public final synchronized void stop()
410      {
411        checkAccess();
412        if (groups == null)
413          return;
414        int i = threads.size();
415        while (--i >= 0)
416          ((Thread) threads.get(i)).stop();
417        i = groups.size();
418        while (--i >= 0)
419          ((ThreadGroup) groups.get(i)).stop();
420      }
421    
422      /**
423       * Interrupt all Threads in this ThreadGroup and its sub-groups. There may
424       * be a security check, <code>checkAccess</code>.
425       *
426       * @throws SecurityException if permission is denied
427       * @see #checkAccess()
428       * @see Thread#interrupt()
429       * @since 1.2
430       */
431      public final synchronized void interrupt()
432      {
433        checkAccess();
434        if (groups == null)
435          return;
436        int i = threads.size();
437        while (--i >= 0)
438          ((Thread) threads.get(i)).interrupt();
439        i = groups.size();
440        while (--i >= 0)
441          ((ThreadGroup) groups.get(i)).interrupt();
442      }
443    
444      /**
445       * Suspend all Threads in this ThreadGroup and its descendants.
446       *
447       * <p>This is inherently unsafe, as suspended threads still hold locks,
448       * which can lead to deadlock.  Hence, there is a security check:
449       * <code>checkAccess()</code>, followed by further checks on each thread
450       * being suspended.
451       *
452       * @throws SecurityException if permission is denied
453       * @see #checkAccess()
454       * @see Thread#suspend()
455       * @deprecated unsafe operation, try not to use
456       */
457    public final synchronized void suspend()    public final synchronized void suspend()
458    {    {
459      checkAccess();      checkAccess();
460      for (int i=0; i<threads.size(); i++)      if (groups == null)
461        {        return;
462          Thread t = (Thread) threads.elementAt(i);      int i = threads.size();
463          t.suspend();      while (--i >= 0)
464        }        ((Thread) threads.get(i)).suspend();
465      for (int i=0; i < groups.size(); i++)      i = groups.size();
466        {      while (--i >= 0)
467          ThreadGroup tg = (ThreadGroup) groups.elementAt(i);        ((ThreadGroup) groups.get(i)).suspend();
468          tg.suspend();    }
469        }  
470    }    /**
471       * Resume all suspended Threads in this ThreadGroup and its descendants.
472    /** Resume all Threads in this ThreadGroup and its descendants.     * To mirror suspend(), there is a security check:
473      * @exception SecurityException if you cannot modify this     * <code>checkAccess()</code>, followed by further checks on each thread
474      *            ThreadGroup or any of its Threads or children     * being resumed.
475      *            ThreadGroups.     *
476      * @deprecated This method relies on Thread.suspend(), which is dangerous.     * @throws SecurityException if permission is denied
477      */     * @see #checkAccess()
478       * @see Thread#suspend()
479       * @deprecated pointless, since suspend is deprecated
480       */
481    public final synchronized void resume()    public final synchronized void resume()
482    {    {
483      checkAccess();      checkAccess();
484      for (int i=0; i < threads.size(); i++)      if (groups == null)
485        {        return;
486          Thread t = (Thread) threads.elementAt(i);      int i = threads.size();
487          t.resume();      while (--i >= 0)
488        }        ((Thread) threads.get(i)).resume();
489      for (int i=0; i < groups.size(); i++)      i = groups.size();
490        {      while (--i >= 0)
491          ThreadGroup tg = (ThreadGroup) groups.elementAt(i);        ((ThreadGroup) groups.get(i)).resume();
492          tg.resume();    }
493        }  
494    }    /**
495       * Destroy this ThreadGroup.  The group must be empty, meaning that all
496    // This is a helper that is used to implement the destroy method.     * threads and sub-groups have completed execution. Daemon groups are
497    private synchronized void checkDestroy ()     * destroyed automatically. There may be a security check,
498    {     * <code>checkAccess</code>.
499      if (! threads.isEmpty())     *
500        throw new IllegalThreadStateException ("ThreadGroup has threads");     * @throws IllegalThreadStateException if the ThreadGroup is not empty, or
501      for (int i=0; i < groups.size(); i++)     *         was previously destroyed
502        {     * @throws SecurityException if permission is denied
503          ThreadGroup tg = (ThreadGroup) groups.elementAt(i);     * @see #checkAccess()
504          tg.checkDestroy();     */
       }  
   }  
   
   /** Destroy this ThreadGroup.  There can be no Threads in it,  
     * and none of its descendants (sub-groups) may have Threads in them.  
     * All its descendants will be destroyed as well.  
     * @exception IllegalThreadStateException if the ThreadGroup or  
     *            its descendants have Threads remaining in them, or  
     *            if the ThreadGroup in question is already destroyed.  
     * @exception SecurityException if you cannot modify this  
     *            ThreadGroup or any of its descendants.  
     */  
505    public final synchronized void destroy()    public final synchronized void destroy()
506    {    {
507      checkAccess();      checkAccess();
508      if (isDestroyed())      if (! threads.isEmpty() || groups == null)
509        throw new IllegalThreadStateException("Already destroyed.");        throw new IllegalThreadStateException();
510      checkDestroy ();      int i = groups.size();
511        while (--i >= 0)
512          ((ThreadGroup) groups.get(i)).destroy();
513        groups = null;
514      if (parent != null)      if (parent != null)
515        parent.removeGroup(this);        parent.removeGroup(this);
     parent = null;  
   
     for (int i=0; i < groups.size(); i++)  
       {  
         ThreadGroup tg = (ThreadGroup) groups.elementAt(i);  
         tg.destroy();  
       }  
516    }    }
517      
518    /** Print out information about this ThreadGroup to System.out.    /**
519      */     * Print out information about this ThreadGroup to System.out. This is
520       * meant for debugging purposes. <b>WARNING:</b> This method is not secure,
521       * and can print the name of threads to standard out even when you cannot
522       * otherwise get at such threads.
523       */
524    public void list()    public void list()
525    {    {
526      list("");      list("");
527    }    }
528    
529    private synchronized void list(String indentation)    /**
530    {     * When a Thread in this ThreadGroup does not catch an exception, the
531      System.out.print(indentation);     * virtual machine calls this method. The default implementation simply
532      System.out.println(toString ());     * passes the call to the parent; then in top ThreadGroup, it will
533      String sub = indentation + "    ";     * ignore ThreadDeath and print the stack trace of any other throwable.
534      for (int i=0; i < threads.size(); i++)     * Override this method if you want to handle the exception in a different
535        {     * manner.
536          Thread t = (Thread) threads.elementAt(i);     *
537          System.out.print(sub);     * @param thread the thread that exited
538          System.out.println(t.toString());     * @param exception the uncaught exception
539        }     * @throws NullPointerException if t is null
540      for (int i=0; i < groups.size(); i++)     * @see ThreadDeath
541        {     * @see System#err
542          ThreadGroup tg = (ThreadGroup) groups.elementAt(i);     * @see Throwable#printStackTrace()
543          tg.list(sub);     */
       }  
   }  
   
   /** When a Thread in this ThreadGroup does not catch an exception,  
     * this method of the ThreadGroup is called.<P>  
     *  
     * ThreadGroup's implementation does the following:<BR>  
     * <OL>  
     * <LI>If there is a parent ThreadGroup, call uncaughtException()  
     *     in the parent.</LI>  
     * <LI>If the Throwable passed is a ThreadDeath, don't do  
     *     anything.</LI>  
     * <LI>Otherwise, call <CODE>exception.printStackTrace().</CODE></LI>  
     * </OL>  
     *  
     * @param thread the thread that exited.  
     * @param exception the uncaught exception.  
     */  
544    public void uncaughtException(Thread thread, Throwable t)    public void uncaughtException(Thread thread, Throwable t)
545    {    {
546      if (parent != null)      if (parent != null)
547        parent.uncaughtException (thread, t);        parent.uncaughtException(thread, t);
548      else if (! (t instanceof ThreadDeath))      else if (! (t instanceof ThreadDeath))
549        {        {
550          if (thread != null)          if (t == null)
551            System.err.print ("Exception in thread \""            throw new NullPointerException();
552                              + thread.getName() + "\" ");          had_uncaught_exception = true;
553          try          try
554            {            {
555              t.printStackTrace(System.err);              if (thread != null)
556            }                System.err.print("Exception in thread \"" + thread.name + "\" ");
557          catch (Throwable x)              t.printStackTrace(System.err);
558            {            }
559              // This means that something is badly screwed up with the runtime,          catch (Throwable x)
560              // or perhaps someone is messing with the SecurityManager. In any            {
561              // case, try to deal with it gracefully.              // This means that something is badly screwed up with the runtime,
562              System.err.println(t);              // or perhaps someone overloaded the Throwable.printStackTrace to
563              System.err.println("*** Got " + x.toString() +              // die. In any case, try to deal with it gracefully.
564                                 " while trying to print stack trace");              try
565            }                {
566          had_uncaught_exception = true;                  System.err.println(t);
567                    System.err.println("*** Got " + x
568                                       + " while trying to print stack trace.");
569                  }
570                catch (Throwable x2)
571                  {
572                    // Here, someone may have overloaded t.toString() or
573                    // x.toString() to die. Give up all hope; we can't even chain
574                    // the exception, because the chain would likewise die.
575                    System.err.println("*** Catastrophic failure while handling "
576                                       + "uncaught exception.");
577                    throw new InternalError();
578                  }
579              }
580        }        }
581    }    }
582    
583    /** Tell the VM whether it may suspend Threads in low memory    /**
584      * situations.     * Originally intended to tell the VM whether it may suspend Threads in
585      * @deprecated This method is unimplemented, because it would rely on     * low memory situations, this method was never implemented by Sun, and
586      *             suspend(), which is deprecated. There is no way for a Java     * is hence a no-op.
587      *             program to determine whether this has any effect whatsoever,     *
588      *             so we don't need it.     * @param allow whether to allow low-memory thread suspension; ignored
589      * @return false     * @return false
590      */     * @since 1.1
591       * @deprecated pointless, since suspend is deprecated
592       */
593    public boolean allowThreadSuspension(boolean allow)    public boolean allowThreadSuspension(boolean allow)
594    {    {
595      return false;      return false;
596    }    }
597    
598    /** Get a human-readable representation of this ThreadGroup.    /**
599      * @return a String representing this ThreadGroup.     * Return a human-readable String representing this ThreadGroup. The format
600      * @specnote Language Spec and Class Libraries book disagree a bit here.     * of the string is:<br>
601      *           We follow the Spec, but add "ThreadGroup" per the book.  We     * <code>getClass().getName() + "[name=" + getName() + ",maxpri="
602      *           include "java.lang" based on the list() example in the Class     * + getMaxPriority() + ']'</code>.
603      *           Libraries book.     *
604      */     * @return a human-readable String representing this ThreadGroup
605    public String toString ()     */
606    {    public String toString()
     return "java.lang.ThreadGroup[name=" + name +  
            ",maxpri=" + maxpri + "]";  
   }  
   
   /** Find out if the current Thread can modify this ThreadGroup.  
     * Calls the current SecurityManager's checkAccess() method to  
     * find out.  If there is none, it assumes everything's OK.  
     * @exception SecurityException if the current Thread cannot  
     *            modify this ThreadGroup.  
     */  
   public final void checkAccess()  
607    {    {
608      SecurityManager sm = System.getSecurityManager();      return getClass().getName() + "[name=" + name + ",maxpri=" + maxpri + ']';
     if (sm != null)  
       sm.checkAccess(this);  
609    }    }
610    
611    // This is called to add a Thread to our internal list.    /**
612       * Implements enumerate.
613       *
614       * @param list the array to put the threads into
615       * @param next the next open slot in the array
616       * @param recurse whether to recurse into descendent ThreadGroups
617       * @return the number of threads put into the array
618       * @throws SecurityException if permission was denied
619       * @throws NullPointerException if list is null
620       * @throws ArrayStoreException if a thread does not fit in the array
621       * @see #enumerate(Thread[])
622       * @see #enumerate(Thread[], boolean)
623       */
624      private int enumerate(Thread[] list, int next, boolean recurse)
625      {
626        checkAccess();
627        if (groups == null)
628          return next;
629        int i = threads.size();
630        while (--i >= 0 && next < list.length)
631          {
632            Thread t = (Thread) threads.get(i);
633            if (t.isAlive())
634              list[next++] = t;
635          }
636        if (recurse)
637          {
638            i = groups.size();
639            while (--i >= 0 && next < list.length)
640              {
641                ThreadGroup g = (ThreadGroup) threads.get(i);
642                next = g.enumerate(list, next, true);
643              }
644          }
645        return next;
646      }
647    
648      /**
649       * Implements enumerate.
650       *
651       * @param list the array to put the groups into
652       * @param next the next open slot in the array
653       * @param recurse whether to recurse into descendent ThreadGroups
654       * @return the number of groups put into the array
655       * @throws SecurityException if permission was denied
656       * @throws NullPointerException if list is null
657       * @throws ArrayStoreException if a group does not fit in the array
658       * @see #enumerate(ThreadGroup[])
659       * @see #enumerate(ThreadGroup[], boolean)
660       */
661      private int enumerate(ThreadGroup[] list, int next, boolean recurse)
662      {
663        checkAccess();
664        if (groups == null)
665          return next;
666        int i = groups.size();
667        while (--i >= 0 && next < list.length)
668          {
669            ThreadGroup g = (ThreadGroup) groups.get(i);
670            list[next++] = g;
671            if (recurse && next != list.length)
672              next = g.enumerate(list, next, true);
673          }
674        return next;
675      }
676    
677      /**
678       * Implements list.
679       *
680       * @param indentation the current level of indentation
681       * @see #list()
682       */
683      private void list(String indentation)
684      {
685        if (groups == null)
686          return;
687        System.out.print(indentation + this);
688        indentation += "    ";
689        int i = threads.size();
690        while (--i >= 0)
691          System.out.println(indentation + threads.get(i));
692        i = groups.size();
693        while (--i >= 0)
694          ((ThreadGroup) groups.get(i)).list(indentation);
695      }
696    
697      /**
698       * Add a thread to the group. Called by Thread constructors.
699       *
700       * @param t the thread to add, non-null
701       * @throws IllegalThreadStateException if the group is destroyed
702       */
703    final synchronized void addThread(Thread t)    final synchronized void addThread(Thread t)
704    {    {
705      if (isDestroyed())      if (groups == null)
706        throw new IllegalThreadStateException ("ThreadGroup is destroyed");        throw new IllegalThreadStateException("ThreadGroup is destroyed");
707          threads.add(t);
     threads.addElement(t);  
708    }    }
709    
710    // This is called to remove a Thread from our internal list.    /**
711       * Called by the VM to remove a thread that has died.
712       *
713       * @param t the thread to remove, non-null
714       * @XXX A ThreadListener to call this might be nice.
715       */
716    final synchronized void removeThread(Thread t)    final synchronized void removeThread(Thread t)
717    {    {
718      if (isDestroyed())      if (groups == null)
719        throw new IllegalThreadStateException ();        return;
720          threads.remove(t);
     threads.removeElement(t);  
721      // Daemon groups are automatically destroyed when all their threads die.      // Daemon groups are automatically destroyed when all their threads die.
722      if (daemon_flag && groups.size() == 0 && threads.size() == 0)      if (daemon_flag && groups.size() == 0 && threads.size() == 0)
723        {        {
724          // We inline destroy to avoid the access check.          // We inline destroy to avoid the access check.
725          if (parent != null)          groups = null;
726            parent.removeGroup(this);          if (parent != null)
727          parent = null;            parent.removeGroup(this);
728        }        }
729    }    }
730    
731    // This is called to add a ThreadGroup to our internal list.    /**
732    final synchronized void addGroup(ThreadGroup g)     * Called when a group is destroyed, to remove it from its parent.
733    {     *
734      groups.addElement(g);     * @param g the destroyed group, non-null
735    }     */
   
   // This is called to remove a ThreadGroup from our internal list.  
736    final synchronized void removeGroup(ThreadGroup g)    final synchronized void removeGroup(ThreadGroup g)
737    {    {
738      groups.removeElement(g);      groups.remove(g);
739      // Daemon groups are automatically destroyed when all their threads die.      // Daemon groups are automatically destroyed when all their threads die.
740      if (daemon_flag && groups.size() == 0 && threads.size() == 0)      if (daemon_flag && groups.size() == 0 && threads.size() == 0)
741        {        {
742          // We inline destroy to avoid the access check.          // We inline destroy to avoid the access check.
743          if (parent != null)          groups = null;
744            parent.removeGroup(this);          if (parent != null)
745          parent = null;            parent.removeGroup(this);
746        }        }
747    }    }
748  }  } // class ThreadGroup

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26