KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > lang > ThreadGroup


1 /*
2  * @(#)ThreadGroup.java 1.63 04/06/17
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.lang;
9
10 import java.io.PrintStream JavaDoc;
11 import sun.misc.VM;
12
13 /**
14  * A thread group represents a set of threads. In addition, a thread
15  * group can also include other thread groups. The thread groups form
16  * a tree in which every thread group except the initial thread group
17  * has a parent.
18  * <p>
19  * A thread is allowed to access information about its own thread
20  * group, but not to access information about its thread group's
21  * parent thread group or any other thread groups.
22  *
23  * @author unascribed
24  * @version 1.63, 06/17/04
25  * @since JDK1.0
26  */

27 /* The locking strategy for this code is to try to lock only one level of the
28  * tree wherever possible, but otherwise to lock from the bottom up.
29  * That is, from child thread groups to parents.
30  * This has the advantage of limiting the number of locks that need to be held
31  * and in particular avoids having to grab the lock for the root thread group,
32  * (or a global lock) which would be a source of contention on a
33  * multi-processor system with many thread groups.
34  * This policy often leads to taking a snapshot of the state of a thread group
35  * and working off of that snapshot, rather than holding the thread group locked
36  * while we work on the children.
37  */

38 public
39 class ThreadGroup implements Thread.UncaughtExceptionHandler JavaDoc {
40     ThreadGroup JavaDoc parent;
41     String JavaDoc name;
42     int maxPriority;
43     boolean destroyed;
44     boolean daemon;
45     boolean vmAllowSuspension;
46
47     int nUnstartedThreads = 0;
48     int nthreads;
49     Thread JavaDoc threads[];
50
51     int ngroups;
52     ThreadGroup JavaDoc groups[];
53
54     /**
55      * Creates an empty Thread group that is not in any Thread group.
56      * This method is used to create the system Thread group.
57      */

58     private ThreadGroup() { // called from C code
59
this.name = "system";
60     this.maxPriority = Thread.MAX_PRIORITY;
61     }
62
63     /**
64      * Constructs a new thread group. The parent of this new group is
65      * the thread group of the currently running thread.
66      * <p>
67      * The <code>checkAccess</code> method of the parent thread group is
68      * called with no arguments; this may result in a security exception.
69      *
70      * @param name the name of the new thread group.
71      * @exception SecurityException if the current thread cannot create a
72      * thread in the specified thread group.
73      * @see java.lang.ThreadGroup#checkAccess()
74      * @since JDK1.0
75      */

76     public ThreadGroup(String JavaDoc 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 JavaDoc parent, String JavaDoc name) {
98     if (parent == null) {
99         throw new NullPointerException JavaDoc();
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 JavaDoc getName() {
117     return name;
118     }
119
120     /**
121      * Returns the parent of this thread group.
122      * <p>
123      * First, if the parent is not <code>null</code>, the
124      * <code>checkAccess</code> method of the parent thread group is
125      * called with no arguments; this may result in a security exception.
126      *
127      * @return the parent of this thread group. The top-level thread group
128      * is the only thread group whose parent is <code>null</code>.
129      * @exception SecurityException if the current thread cannot modify
130      * this thread group.
131      * @see java.lang.ThreadGroup#checkAccess()
132      * @see java.lang.SecurityException
133      * @see java.lang.RuntimePermission
134      * @since JDK1.0
135      */

136     public final ThreadGroup JavaDoc getParent() {
137     if (parent != null)
138         parent.checkAccess();
139     return parent;
140     }
141
142     /**
143      * Returns the maximum priority of this thread group. Threads that are
144      * part of this group cannot have a higher priority than the maximum
145      * priority.
146      *
147      * @return the maximum priority that a thread in this thread group
148      * can have.
149      * @see #setMaxPriority
150      * @since JDK1.0
151      */

152     public final int getMaxPriority() {
153     return maxPriority;
154     }
155
156     /**
157      * Tests if this thread group is a daemon thread group. A
158      * daemon thread group is automatically destroyed when its last
159      * thread is stopped or its last thread group is destroyed.
160      *
161      * @return <code>true</code> if this thread group is a daemon thread group;
162      * <code>false</code> otherwise.
163      * @since JDK1.0
164      */

165     public final boolean isDaemon() {
166     return daemon;
167     }
168
169     /**
170      * Tests if this thread group has been destroyed.
171      *
172      * @return true if this object is destroyed
173      * @since JDK1.1
174      */

175     public synchronized boolean isDestroyed() {
176     return destroyed;
177     }
178
179     /**
180      * Changes the daemon status of this thread group.
181      * <p>
182      * First, the <code>checkAccess</code> method of this thread group is
183      * called with no arguments; this may result in a security exception.
184      * <p>
185      * A daemon thread group is automatically destroyed when its last
186      * thread is stopped or its last thread group is destroyed.
187      *
188      * @param daemon if <code>true</code>, marks this thread group as
189      * a daemon thread group; otherwise, marks this
190      * thread group as normal.
191      * @exception SecurityException if the current thread cannot modify
192      * this thread group.
193      * @see java.lang.SecurityException
194      * @see java.lang.ThreadGroup#checkAccess()
195      * @since JDK1.0
196      */

197     public final void setDaemon(boolean daemon) {
198     checkAccess();
199     this.daemon = daemon;
200     }
201
202     /**
203      * Sets the maximum priority of the group. Threads in the thread
204      * group that already have a higher priority are not affected.
205      * <p>
206      * First, the <code>checkAccess</code> method of this thread group is
207      * called with no arguments; this may result in a security exception.
208      * <p>
209      * If the <code>pri</code> argument is less than
210      * {@link Thread#MIN_PRIORITY} or greater than
211      * {@link Thread#MAX_PRIORITY}, the maximum priority of the group
212      * remains unchanged.
213      * <p>
214      * Otherwise, the priority of this ThreadGroup object is set to the
215      * smaller of the specified <code>pri</code> and the maximum permitted
216      * priority of the parent of this thread group. (If this thread group
217      * is the system thread group, which has no parent, then its maximum
218      * priority is simply set to <code>pri</code>.) Then this method is
219      * called recursively, with <code>pri</code> as its argument, for
220      * every thread group that belongs to this thread group.
221      *
222      * @param pri the new priority of the thread group.
223      * @exception SecurityException if the current thread cannot modify
224      * this thread group.
225      * @see #getMaxPriority
226      * @see java.lang.SecurityException
227      * @see java.lang.ThreadGroup#checkAccess()
228      * @since JDK1.0
229      */

230     public final void setMaxPriority(int pri) {
231     int ngroupsSnapshot;
232     ThreadGroup JavaDoc[] groupsSnapshot;
233     synchronized (this) {
234         checkAccess();
235         if (pri < Thread.MIN_PRIORITY) {
236         maxPriority = Thread.MIN_PRIORITY;
237         } else if (pri < maxPriority) {
238         maxPriority = pri;
239         }
240         ngroupsSnapshot = ngroups;
241         if (groups != null) {
242         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
243         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
244         } else {
245         groupsSnapshot = null;
246         }
247     }
248     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
249         groupsSnapshot[i].setMaxPriority(pri);
250     }
251     }
252
253     /**
254      * Tests if this thread group is either the thread group
255      * argument or one of its ancestor thread groups.
256      *
257      * @param g a thread group.
258      * @return <code>true</code> if this thread group is the thread group
259      * argument or one of its ancestor thread groups;
260      * <code>false</code> otherwise.
261      * @since JDK1.0
262      */

263     public final boolean parentOf(ThreadGroup JavaDoc g) {
264     for (; g != null ; g = g.parent) {
265         if (g == this) {
266         return true;
267         }
268     }
269     return false;
270     }
271
272     /**
273      * Determines if the currently running thread has permission to
274      * modify this thread group.
275      * <p>
276      * If there is a security manager, its <code>checkAccess</code> method
277      * is called with this thread group as its argument. This may result
278      * in throwing a <code>SecurityException</code>.
279      *
280      * @exception SecurityException if the current thread is not allowed to
281      * access this thread group.
282      * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
283      * @since JDK1.0
284      */

285     public final void checkAccess() {
286     SecurityManager JavaDoc security = System.getSecurityManager();
287     if (security != null) {
288         security.checkAccess(this);
289     }
290     }
291
292     /**
293      * Returns an estimate of the number of active threads in this
294      * thread group. The result might not reflect concurrent activity,
295      * and might be affected by the presence of certain system threads.
296      * <p>
297      * Due to the inherently imprecise nature of the result, it is
298      * recommended that this method only be used for informational purposes.
299      *
300      * @return an estimate of the number of active threads in this thread
301      * group and in any other thread group that has this thread
302      * group as an ancestor.
303      * @since JDK1.0
304      */

305     public int activeCount() {
306     int result;
307     // Snapshot sub-group data so we don't hold this lock
308
// while our children are computing.
309
int ngroupsSnapshot;
310     ThreadGroup JavaDoc[] groupsSnapshot;
311     synchronized (this) {
312         if (destroyed) {
313         return 0;
314         }
315         result = nthreads;
316         ngroupsSnapshot = ngroups;
317         if (groups != null) {
318         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
319         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
320         } else {
321         groupsSnapshot = null;
322         }
323     }
324     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
325         result += groupsSnapshot[i].activeCount();
326     }
327     return result;
328     }
329
330     /**
331      * Copies into the specified array every active thread in this
332      * thread group and its subgroups.
333      * <p>
334      * First, the <code>checkAccess</code> method of this thread group is
335      * called with no arguments; this may result in a security exception.
336      * <p>
337      * An application might use the <code>activeCount</code> method to
338      * get an estimate of how big the array should be, however <i>if the
339      * array is too short to hold all the threads, the extra threads are
340      * silently ignored.</i> If it is critical to obtain every active
341      * thread in this thread group and its subgroups, the caller should
342      * verify that the returned int value is strictly less than the length
343      * of <tt>list</tt>.
344      * <p>
345      * Due to the inherent race condition in this method, it is recommended
346      * that the method only be used for informational purposes.
347      *
348      * @param list an array into which to place the list of threads.
349      * @return the number of threads put into the array.
350      * @exception SecurityException if the current thread does not
351      * have permission to enumerate this thread group.
352      * @see java.lang.ThreadGroup#activeCount()
353      * @see java.lang.ThreadGroup#checkAccess()
354      * @since JDK1.0
355      */

356     public int enumerate(Thread JavaDoc list[]) {
357         checkAccess();
358     return enumerate(list, 0, true);
359     }
360
361     /**
362      * Copies into the specified array every active thread in this
363      * thread group. If the <code>recurse</code> flag is
364      * <code>true</code>, references to every active thread in this
365      * thread's subgroups are also included. If the array is too short to
366      * hold all the threads, the extra threads are silently ignored.
367      * <p>
368      * First, the <code>checkAccess</code> method of this thread group is
369      * called with no arguments; this may result in a security exception.
370      * <p>
371      * An application might use the <code>activeCount</code> method to
372      * get an estimate of how big the array should be, however <i>if the
373      * array is too short to hold all the threads, the extra threads are
374      * silently ignored.</i> If it is critical to obtain every active thread
375      * in this thread group, the caller should verify that the returned int
376      * value is strictly less than the length of <tt>list</tt>.
377      * <p>
378      * Due to the inherent race condition in this method, it is recommended
379      * that the method only be used for informational purposes.
380      *
381      * @param list an array into which to place the list of threads.
382      * @param recurse a flag indicating whether also to include threads
383      * in thread groups that are subgroups of this
384      * thread group.
385      * @return the number of threads placed into the array.
386      * @exception SecurityException if the current thread does not
387      * have permission to enumerate this thread group.
388      * @see java.lang.ThreadGroup#activeCount()
389      * @see java.lang.ThreadGroup#checkAccess()
390      * @since JDK1.0
391      */

392     public int enumerate(Thread JavaDoc list[], boolean recurse) {
393         checkAccess();
394     return enumerate(list, 0, recurse);
395     }
396
397     private int enumerate(Thread JavaDoc list[], int n, boolean recurse) {
398     int ngroupsSnapshot = 0;
399     ThreadGroup JavaDoc[] groupsSnapshot = null;
400     synchronized (this) {
401         if (destroyed) {
402         return 0;
403         }
404         int nt = nthreads;
405         if (nt > list.length - n) {
406         nt = list.length - n;
407         }
408         for (int i = 0; i < nt; i++) {
409                 if (threads[i].isAlive()) {
410                     list[n++] = threads[i];
411                 }
412             }
413         if (recurse) {
414         ngroupsSnapshot = ngroups;
415         if (groups != null) {
416             groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
417             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
418         } else {
419             groupsSnapshot = null;
420         }
421         }
422     }
423     if (recurse) {
424         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
425         n = groupsSnapshot[i].enumerate(list, n, true);
426         }
427     }
428     return n;
429     }
430
431     /**
432      * Returns an estimate of the number of active groups in this
433      * thread group. The result might not reflect concurrent activity.
434      * <p>
435      * Due to the inherently imprecise nature of the result, it is
436      * recommended that this method only be used for informational purposes.
437      *
438      * @return the number of active thread groups with this thread group as
439      * an ancestor.
440      * @since JDK1.0
441      */

442     public int activeGroupCount() {
443     int ngroupsSnapshot;
444     ThreadGroup JavaDoc[] groupsSnapshot;
445     synchronized (this) {
446         if (destroyed) {
447         return 0;
448         }
449         ngroupsSnapshot = ngroups;
450         if (groups != null) {
451         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
452         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
453         } else {
454         groupsSnapshot = null;
455         }
456     }
457     int n = ngroupsSnapshot;
458     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
459         n += groupsSnapshot[i].activeGroupCount();
460     }
461     return n;
462     }
463
464     /**
465      * Copies into the specified array references to every active
466      * subgroup in this thread group.
467      * <p>
468      * First, the <code>checkAccess</code> method of this thread group is
469      * called with no arguments; this may result in a security exception.
470      * <p>
471      * An application might use the <code>activeGroupCount</code> method to
472      * get an estimate of how big the array should be, however <i>if the
473      * array is too short to hold all the thread groups, the extra thread
474      * groups are silently ignored.</i> If it is critical to obtain every
475      * active subgroup in this thread group, the caller should verify that
476      * the returned int value is strictly less than the length of
477      * <tt>list</tt>.
478      * <p>
479      * Due to the inherent race condition in this method, it is recommended
480      * that the method only be used for informational purposes.
481      *
482      * @param list an array into which to place the list of thread groups.
483      * @return the number of thread groups put into the array.
484      * @exception SecurityException if the current thread does not
485      * have permission to enumerate this thread group.
486      * @see java.lang.ThreadGroup#activeGroupCount()
487      * @see java.lang.ThreadGroup#checkAccess()
488      * @since JDK1.0
489      */

490     public int enumerate(ThreadGroup JavaDoc list[]) {
491         checkAccess();
492     return enumerate(list, 0, true);
493     }
494
495     /**
496      * Copies into the specified array references to every active
497      * subgroup in this thread group. If the <code>recurse</code> flag is
498      * <code>true</code>, references to all active subgroups of the
499      * subgroups and so forth are also included.
500      * <p>
501      * First, the <code>checkAccess</code> method of this thread group is
502      * called with no arguments; this may result in a security exception.
503      * <p>
504      * An application might use the <code>activeGroupCount</code> method to
505      * get an estimate of how big the array should be, however <i>if the
506      * array is too short to hold all the thread groups, the extra thread
507      * groups are silently ignored.</i> If it is critical to obtain every
508      * active subgroup in this thread group, the caller should verify that
509      * the returned int value is strictly less than the length of
510      * <tt>list</tt>.
511      * <p>
512      * Due to the inherent race condition in this method, it is recommended
513      * that the method only be used for informational purposes.
514      *
515      * @param list an array into which to place the list of threads.
516      * @param recurse a flag indicating whether to recursively enumerate
517      * all included thread groups.
518      * @return the number of thread groups put into the array.
519      * @exception SecurityException if the current thread does not
520      * have permission to enumerate this thread group.
521      * @see java.lang.ThreadGroup#activeGroupCount()
522      * @see java.lang.ThreadGroup#checkAccess()
523      * @since JDK1.0
524      */

525     public int enumerate(ThreadGroup JavaDoc list[], boolean recurse) {
526         checkAccess();
527     return enumerate(list, 0, recurse);
528     }
529
530     private int enumerate(ThreadGroup JavaDoc list[], int n, boolean recurse) {
531     int ngroupsSnapshot = 0;
532     ThreadGroup JavaDoc[] groupsSnapshot = null;
533     synchronized (this) {
534         if (destroyed) {
535         return 0;
536         }
537         int ng = ngroups;
538         if (ng > list.length - n) {
539         ng = list.length - n;
540         }
541         if (ng > 0) {
542         System.arraycopy(groups, 0, list, n, ng);
543         n += ng;
544         }
545         if (recurse) {
546         ngroupsSnapshot = ngroups;
547         if (groups != null) {
548             groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
549             System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
550         } else {
551             groupsSnapshot = null;
552         }
553         }
554     }
555     if (recurse) {
556         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
557         n = groupsSnapshot[i].enumerate(list, n, true);
558         }
559     }
560     return n;
561     }
562
563     /**
564      * Stops all threads in this thread group.
565      * <p>
566      * First, the <code>checkAccess</code> method of this thread group is
567      * called with no arguments; this may result in a security exception.
568      * <p>
569      * This method then calls the <code>stop</code> method on all the
570      * threads in this thread group and in all of its subgroups.
571      *
572      * @exception SecurityException if the current thread is not allowed
573      * to access this thread group or any of the threads in
574      * the thread group.
575      * @see java.lang.SecurityException
576      * @see java.lang.Thread#stop()
577      * @see java.lang.ThreadGroup#checkAccess()
578      * @since JDK1.0
579      * @deprecated This method is inherently unsafe. See
580      * {@link Thread#stop} for details.
581      */

582     @Deprecated JavaDoc
583     public final void stop() {
584         if (stopOrSuspend(false))
585             Thread.currentThread().stop();
586     }
587
588     /**
589      * Interrupts all threads in this thread group.
590      * <p>
591      * First, the <code>checkAccess</code> method of this thread group is
592      * called with no arguments; this may result in a security exception.
593      * <p>
594      * This method then calls the <code>interrupt</code> method on all the
595      * threads in this thread group and in all of its subgroups.
596      *
597      * @exception SecurityException if the current thread is not allowed
598      * to access this thread group or any of the threads in
599      * the thread group.
600      * @see java.lang.Thread#interrupt()
601      * @see java.lang.SecurityException
602      * @see java.lang.ThreadGroup#checkAccess()
603      * @since 1.2
604      */

605     public final void interrupt() {
606     int ngroupsSnapshot;
607     ThreadGroup JavaDoc[] groupsSnapshot;
608     synchronized (this) {
609         checkAccess();
610         for (int i = 0 ; i < nthreads ; i++) {
611         threads[i].interrupt();
612         }
613         ngroupsSnapshot = ngroups;
614         if (groups != null) {
615         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
616         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
617         } else {
618         groupsSnapshot = null;
619         }
620     }
621     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
622         groupsSnapshot[i].interrupt();
623     }
624     }
625
626     /**
627      * Suspends all threads in this thread group.
628      * <p>
629      * First, the <code>checkAccess</code> method of this thread group is
630      * called with no arguments; this may result in a security exception.
631      * <p>
632      * This method then calls the <code>suspend</code> method on all the
633      * threads in this thread group and in all of its subgroups.
634      *
635      * @exception SecurityException if the current thread is not allowed
636      * to access this thread group or any of the threads in
637      * the thread group.
638      * @see java.lang.Thread#suspend()
639      * @see java.lang.SecurityException
640      * @see java.lang.ThreadGroup#checkAccess()
641      * @since JDK1.0
642      * @deprecated This method is inherently deadlock-prone. See
643      * {@link Thread#suspend} for details.
644      */

645     @Deprecated JavaDoc
646     public final void suspend() {
647         if (stopOrSuspend(true))
648             Thread.currentThread().suspend();
649     }
650
651     /**
652      * Helper method: recursively stops or suspends (as directed by the
653      * boolean argument) all of the threads in this thread group and its
654      * subgroups, except the current thread. This method returns true
655      * if (and only if) the current thread is found to be in this thread
656      * group or one of its subgroups.
657      */

658     private boolean stopOrSuspend(boolean suspend) {
659         boolean suicide = false;
660         Thread JavaDoc us = Thread.currentThread();
661     int ngroupsSnapshot;
662     ThreadGroup JavaDoc[] groupsSnapshot = null;
663     synchronized (this) {
664         checkAccess();
665         for (int i = 0 ; i < nthreads ; i++) {
666                 if (threads[i]==us)
667                     suicide = true;
668                 else if (suspend)
669                     threads[i].suspend();
670                 else
671                     threads[i].stop();
672         }
673
674         ngroupsSnapshot = ngroups;
675         if (groups != null) {
676         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
677         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
678         }
679     }
680     for (int i = 0 ; i < ngroupsSnapshot ; i++)
681         suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
682
683         return suicide;
684     }
685
686     /**
687      * Resumes all threads in this thread group.
688      * <p>
689      * First, the <code>checkAccess</code> method of this thread group is
690      * called with no arguments; this may result in a security exception.
691      * <p>
692      * This method then calls the <code>resume</code> method on all the
693      * threads in this thread group and in all of its sub groups.
694      *
695      * @exception SecurityException if the current thread is not allowed to
696      * access this thread group or any of the threads in the
697      * thread group.
698      * @see java.lang.SecurityException
699      * @see java.lang.Thread#resume()
700      * @see java.lang.ThreadGroup#checkAccess()
701      * @since JDK1.0
702      * @deprecated This method is used solely in conjunction with
703      * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
704      * both of which have been deprecated, as they are inherently
705      * deadlock-prone. See {@link Thread#suspend} for details.
706      */

707     @Deprecated JavaDoc
708     public final void resume() {
709     int ngroupsSnapshot;
710     ThreadGroup JavaDoc[] groupsSnapshot;
711     synchronized (this) {
712         checkAccess();
713         for (int i = 0 ; i < nthreads ; i++) {
714         threads[i].resume();
715         }
716         ngroupsSnapshot = ngroups;
717         if (groups != null) {
718         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
719         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
720         } else {
721         groupsSnapshot = null;
722         }
723     }
724     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
725         groupsSnapshot[i].resume();
726     }
727     }
728
729     /**
730      * Destroys this thread group and all of its subgroups. This thread
731      * group must be empty, indicating that all threads that had been in
732      * this thread group have since stopped.
733      * <p>
734      * First, the <code>checkAccess</code> method of this thread group is
735      * called with no arguments; this may result in a security exception.
736      *
737      * @exception IllegalThreadStateException if the thread group is not
738      * empty or if the thread group has already been destroyed.
739      * @exception SecurityException if the current thread cannot modify this
740      * thread group.
741      * @see java.lang.ThreadGroup#checkAccess()
742      * @since JDK1.0
743      */

744     public final void destroy() {
745     int ngroupsSnapshot;
746     ThreadGroup JavaDoc[] groupsSnapshot;
747     synchronized (this) {
748         checkAccess();
749         if (destroyed || (nthreads > 0)) {
750         throw new IllegalThreadStateException JavaDoc();
751         }
752         ngroupsSnapshot = ngroups;
753         if (groups != null) {
754         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
755         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
756         } else {
757         groupsSnapshot = null;
758         }
759         if (parent != null) {
760         destroyed = true;
761         ngroups = 0;
762         groups = null;
763         nthreads = 0;
764         threads = null;
765         }
766     }
767     for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
768         groupsSnapshot[i].destroy();
769     }
770     if (parent != null) {
771         parent.remove(this);
772     }
773     }
774
775     /**
776      * Adds the specified Thread group to this group.
777      * @param g the specified Thread group to be added
778      * @exception IllegalThreadStateException If the Thread group has been destroyed.
779      */

780     private final void add(ThreadGroup JavaDoc g){
781     synchronized (this) {
782         if (destroyed) {
783         throw new IllegalThreadStateException JavaDoc();
784         }
785         if (groups == null) {
786         groups = new ThreadGroup JavaDoc[4];
787         } else if (ngroups == groups.length) {
788         ThreadGroup JavaDoc newgroups[] = new ThreadGroup JavaDoc[ngroups * 2];
789         System.arraycopy(groups, 0, newgroups, 0, ngroups);
790         groups = newgroups;
791         }
792         groups[ngroups] = g;
793
794         // This is done last so it doesn't matter in case the
795
// thread is killed
796
ngroups++;
797     }
798     }
799
800     /**
801      * Removes the specified Thread group from this group.
802      * @param g the Thread group to be removed
803      * @return if this Thread has already been destroyed.
804      */

805     private void remove(ThreadGroup JavaDoc g) {
806     synchronized (this) {
807         if (destroyed) {
808         return;
809         }
810         for (int i = 0 ; i < ngroups ; i++) {
811         if (groups[i] == g) {
812             ngroups -= 1;
813             System.arraycopy(groups, i + 1, groups, i, ngroups - i);
814             // Zap dangling reference to the dead group so that
815
// the garbage collector will collect it.
816
groups[ngroups] = null;
817             break;
818         }
819         }
820         if (nthreads == 0) {
821         notifyAll();
822         }
823             if (daemon && (nthreads == 0) &&
824                 (nUnstartedThreads == 0) && (ngroups == 0))
825             {
826         destroy();
827         }
828     }
829     }
830     
831
832     /**
833      * Increments the count of unstarted threads in the thread group.
834      * Unstarted threads are not added to the thread group so that they
835      * can be collected if they are never started, but they must be
836      * counted so that daemon thread groups with unstarted threads in
837      * them are not destroyed.
838      */

839     void addUnstarted() {
840         synchronized(this) {
841             if (destroyed) {
842                 throw new IllegalThreadStateException JavaDoc();
843             }
844             nUnstartedThreads++;
845         }
846     }
847
848     /**
849      * Adds the specified Thread to this group.
850      * @param t the Thread to be added
851      * @exception IllegalThreadStateException If the Thread group has been destroyed.
852      */

853     void add(Thread JavaDoc t) {
854     synchronized (this) {
855         if (destroyed) {
856         throw new IllegalThreadStateException JavaDoc();
857         }
858         if (threads == null) {
859         threads = new Thread JavaDoc[4];
860         } else if (nthreads == threads.length) {
861         Thread JavaDoc newthreads[] = new Thread JavaDoc[nthreads * 2];
862         System.arraycopy(threads, 0, newthreads, 0, nthreads);
863         threads = newthreads;
864         }
865         threads[nthreads] = t;
866
867         // This is done last so it doesn't matter in case the
868
// thread is killed
869
nthreads++;
870             nUnstartedThreads--;
871     }
872     }
873
874     /**
875      * Removes the specified Thread from this group.
876      * @param t the Thread to be removed
877      * @return if the Thread has already been destroyed.
878      */

879     void remove(Thread JavaDoc t) {
880     synchronized (this) {
881         if (destroyed) {
882         return;
883         }
884         for (int i = 0 ; i < nthreads ; i++) {
885         if (threads[i] == t) {
886             System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
887             // Zap dangling reference to the dead thread so that
888
// the garbage collector will collect it.
889
threads[nthreads] = null;
890             break;
891         }
892         }
893         if (nthreads == 0) {
894         notifyAll();
895         }
896             if (daemon && (nthreads == 0) &&
897                 (nUnstartedThreads == 0) && (ngroups == 0))
898             {
899         destroy();
900         }
901     }
902     }
903
904     /**
905      * Prints information about this thread group to the standard
906      * output. This method is useful only for debugging.
907      *
908      * @since JDK1.0
909      */

910     public void list() {
911     list(System.out, 0);
912     }
913     void list(PrintStream JavaDoc out, int indent) {
914     int ngroupsSnapshot;
915     ThreadGroup JavaDoc[] groupsSnapshot;
916     synchronized (this) {
917         for (int j = 0 ; j < indent ; j++) {
918         out.print(" ");
919         }
920         out.println(this);
921         indent += 4;
922         for (int i = 0 ; i < nthreads ; i++) {
923         for (int j = 0 ; j < indent ; j++) {
924             out.print(" ");
925         }
926         out.println(threads[i]);
927         }
928         ngroupsSnapshot = ngroups;
929         if (groups != null) {
930         groupsSnapshot = new ThreadGroup JavaDoc[ngroupsSnapshot];
931         System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
932         } else {
933         groupsSnapshot = null;
934         }
935     }
936     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
937         groupsSnapshot[i].list(out, indent);
938     }
939     }
940
941     /**
942      * Called by the Java Virtual Machine when a thread in this
943      * thread group stops because of an uncaught exception, and the thread
944      * does not have a specific {@link Thread.UncaughtExceptionHandler}
945      * installed.
946      * <p>
947      * The <code>uncaughtException</code> method of
948      * <code>ThreadGroup</code> does the following:
949      * <ul>
950      * <li>If this thread group has a parent thread group, the
951      * <code>uncaughtException</code> method of that parent is called
952      * with the same two arguments.
953      * <li>Otherwise, this method checks to see if there is a
954      * {@linkplain Thread#getDefaultUncaughtExceptionHandler default
955      * uncaught exception handler} installed, and if so, its
956      * <code>uncaughtException</code> method is called with the same
957      * two arguments.
958      * <li>Otherwise, this method determines if the <code>Throwable</code>
959      * argument is an instance of {@link ThreadDeath}. If so, nothing
960      * special is done. Otherwise, a message containing the
961      * thread's name, as returned from the thread's {@link
962      * Thread#getName getName} method, and a stack backtrace,
963      * using the <code>Throwable</code>'s {@link
964      * Throwable#printStackTrace printStackTrace} method, is
965      * printed to the {@linkplain System#err standard error stream}.
966      * </ul>
967      * <p>
968      * Applications can override this method in subclasses of
969      * <code>ThreadGroup</code> to provide alternative handling of
970      * uncaught exceptions.
971      *
972      * @param t the thread that is about to exit.
973      * @param e the uncaught exception.
974      * @since JDK1.0
975      */

976     public void uncaughtException(Thread JavaDoc t, Throwable JavaDoc e) {
977     if (parent != null) {
978         parent.uncaughtException(t, e);
979     } else {
980             Thread.UncaughtExceptionHandler JavaDoc ueh =
981                 Thread.getDefaultUncaughtExceptionHandler();
982             if (ueh != null) {
983                 ueh.uncaughtException(t, e);
984             } else if (!(e instanceof ThreadDeath JavaDoc)) {
985         System.err.print("Exception in thread \""
986                  + t.getName() + "\" ");
987                 e.printStackTrace(System.err);
988             }
989         }
990     }
991
992     /**
993      * Used by VM to control lowmem implicit suspension.
994      *
995      * @param b boolean to allow or disallow suspension
996      * @return true on success
997      * @since JDK1.1
998      * @deprecated The definition of this call depends on {@link #suspend},
999      * which is deprecated. Further, the behavior of this call
1000     * was never specified.
1001     */

1002    @Deprecated JavaDoc
1003    public boolean allowThreadSuspension(boolean b) {
1004    this.vmAllowSuspension = b;
1005    if (!b) {
1006        VM.unsuspendSomeThreads();
1007    }
1008    return true;
1009    }
1010
1011    /**
1012     * Returns a string representation of this Thread group.
1013     *
1014     * @return a string representation of this thread group.
1015     * @since JDK1.0
1016     */

1017    public String JavaDoc toString() {
1018    return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
1019    }
1020}
1021
Popular Tags