1 /*
2  * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.lang;
27
28 import java.io.PrintStream;
29 import java.util.Arrays;
30 import jdk.internal.misc.VM;
31
32 /**
33  * A thread group represents a set of threads. In addition, a thread
34  * group can also include other thread groups. The thread groups form
35  * a tree in which every thread group except the initial thread group
36  * has a parent.
37  * <p>
38  * A thread is allowed to access information about its own thread
39  * group, but not to access information about its thread group's
40  * parent thread group or any other thread groups.
41  *
42  * @author  unascribed
43  * @since   1.0
44  */

45 /* The locking strategy for this code is to try to lock only one level of the
46  * tree wherever possible, but otherwise to lock from the bottom up.
47  * That is, from child thread groups to parents.
48  * This has the advantage of limiting the number of locks that need to be held
49  * and in particular avoids having to grab the lock for the root thread group,
50  * (or a global lock) which would be a source of contention on a
51  * multi-processor system with many thread groups.
52  * This policy often leads to taking a snapshot of the state of a thread group
53  * and working off of that snapshot, rather than holding the thread group locked
54  * while we work on the children.
55  */

56 public
57 class ThreadGroup implements Thread.UncaughtExceptionHandler {
58     private final ThreadGroup parent;
59     String name;
60     int maxPriority;
61     boolean destroyed;
62     boolean daemon;
63
64     int nUnstartedThreads = 0;
65     int nthreads;
66     Thread threads[];
67
68     int ngroups;
69     ThreadGroup groups[];
70
71     /**
72      * Creates an empty Thread group that is not in any Thread group.
73      * This method is used to create the system Thread group.
74      */

75     private ThreadGroup() {     // called from C code
76         this.name = "system";
77         this.maxPriority = Thread.MAX_PRIORITY;
78         this.parent = null;
79     }
80
81     /**
82      * Constructs a new thread group. The parent of this new group is
83      * the thread group of the currently running thread.
84      * <p>
85      * The {@code checkAccess} method of the parent thread group is
86      * called with no arguments; this may result in a security exception.
87      *
88      * @param   name   the name of the new thread group.
89      * @throws  SecurityException  if the current thread cannot create a
90      *               thread in the specified thread group.
91      * @see     java.lang.ThreadGroup#checkAccess()
92      * @since   1.0
93      */

94     public ThreadGroup(String name) {
95         this(Thread.currentThread().getThreadGroup(), name);
96     }
97
98     /**
99      * Creates a new thread group. The parent of this new group is the
100      * specified thread group.
101      * <p>
102      * The {@code checkAccess} method of the parent thread group is
103      * called with no arguments; this may result in a security exception.
104      *
105      * @param     parent   the parent thread group.
106      * @param     name     the name of the new thread group.
107      * @throws    NullPointerException  if the thread group argument is
108      *               {@code null}.
109      * @throws    SecurityException  if the current thread cannot create a
110      *               thread in the specified thread group.
111      * @see     java.lang.SecurityException
112      * @see     java.lang.ThreadGroup#checkAccess()
113      * @since   1.0
114      */

115     public ThreadGroup(ThreadGroup parent, String name) {
116         this(checkParentAccess(parent), parent, name);
117     }
118
119     private ThreadGroup(Void unused, ThreadGroup parent, String name) {
120         this.name = name;
121         this.maxPriority = parent.maxPriority;
122         this.daemon = parent.daemon;
123         this.parent = parent;
124         parent.add(this);
125     }
126
127     /*
128      * @throws  NullPointerException  if the parent argument is {@code null}
129      * @throws  SecurityException     if the current thread cannot create a
130      *                                thread in the specified thread group.
131      */

132     private static Void checkParentAccess(ThreadGroup parent) {
133         parent.checkAccess();
134         return null;
135     }
136
137     /**
138      * Returns the name of this thread group.
139      *
140      * @return  the name of this thread group.
141      * @since   1.0
142      */

143     public final String getName() {
144         return name;
145     }
146
147     /**
148      * Returns the parent of this thread group.
149      * <p>
150      * First, if the parent is not {@code null}, the
151      * {@code checkAccess} method of the parent thread group is
152      * called with no arguments; this may result in a security exception.
153      *
154      * @return  the parent of this thread group. The top-level thread group
155      *          is the only thread group whose parent is {@code null}.
156      * @throws  SecurityException  if the current thread cannot modify
157      *               this thread group.
158      * @see        java.lang.ThreadGroup#checkAccess()
159      * @see        java.lang.SecurityException
160      * @see        java.lang.RuntimePermission
161      * @since   1.0
162      */

163     public final ThreadGroup getParent() {
164         if (parent != null)
165             parent.checkAccess();
166         return parent;
167     }
168
169     /**
170      * Returns the maximum priority of this thread group. Threads that are
171      * part of this group cannot have a higher priority than the maximum
172      * priority.
173      *
174      * @return  the maximum priority that a thread in this thread group
175      *          can have.
176      * @see     #setMaxPriority
177      * @since   1.0
178      */

179     public final int getMaxPriority() {
180         return maxPriority;
181     }
182
183     /**
184      * Tests if this thread group is a daemon thread group. A
185      * daemon thread group is automatically destroyed when its last
186      * thread is stopped or its last thread group is destroyed.
187      *
188      * @return  {@code trueif this thread group is a daemon thread group;
189      *          {@code false} otherwise.
190      * @since   1.0
191      */

192     public final boolean isDaemon() {
193         return daemon;
194     }
195
196     /**
197      * Tests if this thread group has been destroyed.
198      *
199      * @return  true if this object is destroyed
200      * @since   1.1
201      */

202     public synchronized boolean isDestroyed() {
203         return destroyed;
204     }
205
206     /**
207      * Changes the daemon status of this thread group.
208      * <p>
209      * First, the {@code checkAccess} method of this thread group is
210      * called with no arguments; this may result in a security exception.
211      * <p>
212      * A daemon thread group is automatically destroyed when its last
213      * thread is stopped or its last thread group is destroyed.
214      *
215      * @param      daemon   if {@code true}, marks this thread group as
216      *                      a daemon thread group; otherwise, marks this
217      *                      thread group as normal.
218      * @throws     SecurityException  if the current thread cannot modify
219      *               this thread group.
220      * @see        java.lang.SecurityException
221      * @see        java.lang.ThreadGroup#checkAccess()
222      * @since      1.0
223      */

224     public final void setDaemon(boolean daemon) {
225         checkAccess();
226         this.daemon = daemon;
227     }
228
229     /**
230      * Sets the maximum priority of the group. Threads in the thread
231      * group that already have a higher priority are not affected.
232      * <p>
233      * First, the {@code checkAccess} method of this thread group is
234      * called with no arguments; this may result in a security exception.
235      * <p>
236      * If the {@code pri} argument is less than
237      * {@link Thread#MIN_PRIORITY} or greater than
238      * {@link Thread#MAX_PRIORITY}, the maximum priority of the group
239      * remains unchanged.
240      * <p>
241      * Otherwise, the priority of this ThreadGroup object is set to the
242      * smaller of the specified {@code pri} and the maximum permitted
243      * priority of the parent of this thread group. (If this thread group
244      * is the system thread group, which has no parent, then its maximum
245      * priority is simply set to {@code pri}.) Then this method is
246      * called recursively, with {@code pri} as its argument, for
247      * every thread group that belongs to this thread group.
248      *
249      * @param      pri   the new priority of the thread group.
250      * @throws     SecurityException  if the current thread cannot modify
251      *               this thread group.
252      * @see        #getMaxPriority
253      * @see        java.lang.SecurityException
254      * @see        java.lang.ThreadGroup#checkAccess()
255      * @since      1.0
256      */

257     public final void setMaxPriority(int pri) {
258         int ngroupsSnapshot;
259         ThreadGroup[] groupsSnapshot;
260         synchronized (this) {
261             checkAccess();
262             if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
263                 return;
264             }
265             maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
266             ngroupsSnapshot = ngroups;
267             if (groups != null) {
268                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
269             } else {
270                 groupsSnapshot = null;
271             }
272         }
273         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
274             groupsSnapshot[i].setMaxPriority(pri);
275         }
276     }
277
278     /**
279      * Tests if this thread group is either the thread group
280      * argument or one of its ancestor thread groups.
281      *
282      * @param   g   a thread group.
283      * @return  {@code trueif this thread group is the thread group
284      *          argument or one of its ancestor thread groups;
285      *          {@code false} otherwise.
286      * @since   1.0
287      */

288     public final boolean parentOf(ThreadGroup g) {
289         for (; g != null ; g = g.parent) {
290             if (g == this) {
291                 return true;
292             }
293         }
294         return false;
295     }
296
297     /**
298      * Determines if the currently running thread has permission to
299      * modify this thread group.
300      * <p>
301      * If there is a security manager, its {@code checkAccess} method
302      * is called with this thread group as its argument. This may result
303      * in throwing a {@code SecurityException}.
304      *
305      * @throws     SecurityException  if the current thread is not allowed to
306      *               access this thread group.
307      * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
308      * @since      1.0
309      */

310     public final void checkAccess() {
311         SecurityManager security = System.getSecurityManager();
312         if (security != null) {
313             security.checkAccess(this);
314         }
315     }
316
317     /**
318      * Returns an estimate of the number of active threads in this thread
319      * group and its subgroups. Recursively iterates over all subgroups in
320      * this thread group.
321      *
322      * <p> The value returned is only an estimate because the number of
323      * threads may change dynamically while this method traverses internal
324      * data structures, and might be affected by the presence of certain
325      * system threads. This method is intended primarily for debugging
326      * and monitoring purposes.
327      *
328      * @return  an estimate of the number of active threads in this thread
329      *          group and in any other thread group that has this thread
330      *          group as an ancestor
331      *
332      * @since   1.0
333      */

334     public int activeCount() {
335         int result;
336         // Snapshot sub-group data so we don't hold this lock
337         // while our children are computing.
338         int ngroupsSnapshot;
339         ThreadGroup[] groupsSnapshot;
340         synchronized (this) {
341             if (destroyed) {
342                 return 0;
343             }
344             result = nthreads;
345             ngroupsSnapshot = ngroups;
346             if (groups != null) {
347                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
348             } else {
349                 groupsSnapshot = null;
350             }
351         }
352         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
353             result += groupsSnapshot[i].activeCount();
354         }
355         return result;
356     }
357
358     /**
359      * Copies into the specified array every active thread in this
360      * thread group and its subgroups.
361      *
362      * <p> An invocation of this method behaves in exactly the same
363      * way as the invocation
364      *
365      * <blockquote>
366      * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}
367      * </blockquote>
368      *
369      * @param  list
370      *         an array into which to put the list of threads
371      *
372      * @return  the number of threads put into the array
373      *
374      * @throws  SecurityException
375      *          if {@linkplain #checkAccess checkAccess} determines that
376      *          the current thread cannot access this thread group
377      *
378      * @since   1.0
379      */

380     public int enumerate(Thread list[]) {
381         checkAccess();
382         return enumerate(list, 0, true);
383     }
384
385     /**
386      * Copies into the specified array every active thread in this
387      * thread group. If {@code recurse} is {@code true},
388      * this method recursively enumerates all subgroups of this
389      * thread group and references to every active thread in these
390      * subgroups are also included. If the array is too short to
391      * hold all the threads, the extra threads are silently ignored.
392      *
393      * <p> An application might use the {@linkplain #activeCount activeCount}
394      * method to get an estimate of how big the array should be, however
395      * <i>if the array is too short to hold all the threads, the extra threads
396      * are silently ignored.</i>  If it is critical to obtain every active
397      * thread in this thread group, the caller should verify that the returned
398      * int value is strictly less than the length of {@code list}.
399      *
400      * <p> Due to the inherent race condition in this method, it is recommended
401      * that the method only be used for debugging and monitoring purposes.
402      *
403      * @param  list
404      *         an array into which to put the list of threads
405      *
406      * @param  recurse
407      *         if {@code true}, recursively enumerate all subgroups of this
408      *         thread group
409      *
410      * @return  the number of threads put into the array
411      *
412      * @throws  SecurityException
413      *          if {@linkplain #checkAccess checkAccess} determines that
414      *          the current thread cannot access this thread group
415      *
416      * @since   1.0
417      */

418     public int enumerate(Thread list[], boolean recurse) {
419         checkAccess();
420         return enumerate(list, 0, recurse);
421     }
422
423     private int enumerate(Thread list[], int n, boolean recurse) {
424         int ngroupsSnapshot = 0;
425         ThreadGroup[] groupsSnapshot = null;
426         synchronized (this) {
427             if (destroyed) {
428                 return 0;
429             }
430             int nt = nthreads;
431             if (nt > list.length - n) {
432                 nt = list.length - n;
433             }
434             for (int i = 0; i < nt; i++) {
435                 if (threads[i].isAlive()) {
436                     list[n++] = threads[i];
437                 }
438             }
439             if (recurse) {
440                 ngroupsSnapshot = ngroups;
441                 if (groups != null) {
442                     groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
443                 } else {
444                     groupsSnapshot = null;
445                 }
446             }
447         }
448         if (recurse) {
449             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
450                 n = groupsSnapshot[i].enumerate(list, n, true);
451             }
452         }
453         return n;
454     }
455
456     /**
457      * Returns an estimate of the number of active groups in this
458      * thread group and its subgroups. Recursively iterates over
459      * all subgroups in this thread group.
460      *
461      * <p> The value returned is only an estimate because the number of
462      * thread groups may change dynamically while this method traverses
463      * internal data structures. This method is intended primarily for
464      * debugging and monitoring purposes.
465      *
466      * @return  the number of active thread groups with this thread group as
467      *          an ancestor
468      *
469      * @since   1.0
470      */

471     public int activeGroupCount() {
472         int ngroupsSnapshot;
473         ThreadGroup[] groupsSnapshot;
474         synchronized (this) {
475             if (destroyed) {
476                 return 0;
477             }
478             ngroupsSnapshot = ngroups;
479             if (groups != null) {
480                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
481             } else {
482                 groupsSnapshot = null;
483             }
484         }
485         int n = ngroupsSnapshot;
486         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
487             n += groupsSnapshot[i].activeGroupCount();
488         }
489         return n;
490     }
491
492     /**
493      * Copies into the specified array references to every active
494      * subgroup in this thread group and its subgroups.
495      *
496      * <p> An invocation of this method behaves in exactly the same
497      * way as the invocation
498      *
499      * <blockquote>
500      * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)}
501      * </blockquote>
502      *
503      * @param  list
504      *         an array into which to put the list of thread groups
505      *
506      * @return  the number of thread groups put into the array
507      *
508      * @throws  SecurityException
509      *          if {@linkplain #checkAccess checkAccess} determines that
510      *          the current thread cannot access this thread group
511      *
512      * @since   1.0
513      */

514     public int enumerate(ThreadGroup list[]) {
515         checkAccess();
516         return enumerate(list, 0, true);
517     }
518
519     /**
520      * Copies into the specified array references to every active
521      * subgroup in this thread group. If {@code recurse} is
522      * {@code true}, this method recursively enumerates all subgroups of this
523      * thread group and references to every active thread group in these
524      * subgroups are also included.
525      *
526      * <p> An application might use the
527      * {@linkplain #activeGroupCount activeGroupCount} method to
528      * get an estimate of how big the array should be, however <i>if the
529      * array is too short to hold all the thread groups, the extra thread
530      * groups are silently ignored.</i>  If it is critical to obtain every
531      * active subgroup in this thread group, the caller should verify that
532      * the returned int value is strictly less than the length of
533      * {@code list}.
534      *
535      * <p> Due to the inherent race condition in this method, it is recommended
536      * that the method only be used for debugging and monitoring purposes.
537      *
538      * @param  list
539      *         an array into which to put the list of thread groups
540      *
541      * @param  recurse
542      *         if {@code true}, recursively enumerate all subgroups
543      *
544      * @return  the number of thread groups put into the array
545      *
546      * @throws  SecurityException
547      *          if {@linkplain #checkAccess checkAccess} determines that
548      *          the current thread cannot access this thread group
549      *
550      * @since   1.0
551      */

552     public int enumerate(ThreadGroup list[], boolean recurse) {
553         checkAccess();
554         return enumerate(list, 0, recurse);
555     }
556
557     private int enumerate(ThreadGroup list[], int n, boolean recurse) {
558         int ngroupsSnapshot = 0;
559         ThreadGroup[] groupsSnapshot = null;
560         synchronized (this) {
561             if (destroyed) {
562                 return 0;
563             }
564             int ng = ngroups;
565             if (ng > list.length - n) {
566                 ng = list.length - n;
567             }
568             if (ng > 0) {
569                 System.arraycopy(groups, 0, list, n, ng);
570                 n += ng;
571             }
572             if (recurse) {
573                 ngroupsSnapshot = ngroups;
574                 if (groups != null) {
575                     groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
576                 } else {
577                     groupsSnapshot = null;
578                 }
579             }
580         }
581         if (recurse) {
582             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
583                 n = groupsSnapshot[i].enumerate(list, n, true);
584             }
585         }
586         return n;
587     }
588
589     /**
590      * Stops all threads in this thread group.
591      * <p>
592      * First, the {@code checkAccess} method of this thread group is
593      * called with no arguments; this may result in a security exception.
594      * <p>
595      * This method then calls the {@code stop} method on all the
596      * threads in this thread group and in all of its subgroups.
597      *
598      * @throws     SecurityException  if the current thread is not allowed
599      *               to access this thread group or any of the threads in
600      *               the thread group.
601      * @see        java.lang.SecurityException
602      * @see        java.lang.Thread#stop()
603      * @see        java.lang.ThreadGroup#checkAccess()
604      * @since      1.0
605      * @deprecated    This method is inherently unsafe.  See
606      *     {@link Thread#stop} for details.
607      */

608     @Deprecated(since="1.2")
609     public final void stop() {
610         if (stopOrSuspend(false))
611             Thread.currentThread().stop();
612     }
613
614     /**
615      * Interrupts all threads in this thread group.
616      * <p>
617      * First, the {@code checkAccess} method of this thread group is
618      * called with no arguments; this may result in a security exception.
619      * <p>
620      * This method then calls the {@code interrupt} method on all the
621      * threads in this thread group and in all of its subgroups.
622      *
623      * @throws     SecurityException  if the current thread is not allowed
624      *               to access this thread group or any of the threads in
625      *               the thread group.
626      * @see        java.lang.Thread#interrupt()
627      * @see        java.lang.SecurityException
628      * @see        java.lang.ThreadGroup#checkAccess()
629      * @since      1.2
630      */

631     public final void interrupt() {
632         int ngroupsSnapshot;
633         ThreadGroup[] groupsSnapshot;
634         synchronized (this) {
635             checkAccess();
636             for (int i = 0 ; i < nthreads ; i++) {
637                 threads[i].interrupt();
638             }
639             ngroupsSnapshot = ngroups;
640             if (groups != null) {
641                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
642             } else {
643                 groupsSnapshot = null;
644             }
645         }
646         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
647             groupsSnapshot[i].interrupt();
648         }
649     }
650
651     /**
652      * Suspends all threads in this thread group.
653      * <p>
654      * First, the {@code checkAccess} method of this thread group is
655      * called with no arguments; this may result in a security exception.
656      * <p>
657      * This method then calls the {@code suspend} method on all the
658      * threads in this thread group and in all of its subgroups.
659      *
660      * @throws     SecurityException  if the current thread is not allowed
661      *               to access this thread group or any of the threads in
662      *               the thread group.
663      * @see        java.lang.Thread#suspend()
664      * @see        java.lang.SecurityException
665      * @see        java.lang.ThreadGroup#checkAccess()
666      * @since      1.0
667      * @deprecated    This method is inherently deadlock-prone.  See
668      *     {@link Thread#suspend} for details.
669      */

670     @Deprecated(since="1.2")
671     @SuppressWarnings("deprecation")
672     public final void suspend() {
673         if (stopOrSuspend(true))
674             Thread.currentThread().suspend();
675     }
676
677     /**
678      * Helper method: recursively stops or suspends (as directed by the
679      * boolean argument) all of the threads in this thread group and its
680      * subgroups, except the current thread.  This method returns true
681      * if (and only if) the current thread is found to be in this thread
682      * group or one of its subgroups.
683      */

684     @SuppressWarnings("deprecation")
685     private boolean stopOrSuspend(boolean suspend) {
686         boolean suicide = false;
687         Thread us = Thread.currentThread();
688         int ngroupsSnapshot;
689         ThreadGroup[] groupsSnapshot = null;
690         synchronized (this) {
691             checkAccess();
692             for (int i = 0 ; i < nthreads ; i++) {
693                 if (threads[i]==us)
694                     suicide = true;
695                 else if (suspend)
696                     threads[i].suspend();
697                 else
698                     threads[i].stop();
699             }
700
701             ngroupsSnapshot = ngroups;
702             if (groups != null) {
703                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
704             }
705         }
706         for (int i = 0 ; i < ngroupsSnapshot ; i++)
707             suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
708
709         return suicide;
710     }
711
712     /**
713      * Resumes all threads in this thread group.
714      * <p>
715      * First, the {@code checkAccess} method of this thread group is
716      * called with no arguments; this may result in a security exception.
717      * <p>
718      * This method then calls the {@code resume} method on all the
719      * threads in this thread group and in all of its sub groups.
720      *
721      * @throws     SecurityException  if the current thread is not allowed to
722      *               access this thread group or any of the threads in the
723      *               thread group.
724      * @see        java.lang.SecurityException
725      * @see        java.lang.Thread#resume()
726      * @see        java.lang.ThreadGroup#checkAccess()
727      * @since      1.0
728      * @deprecated    This method is used solely in conjunction with
729      *       {@code Thread.suspend} and {@code ThreadGroup.suspend},
730      *       both of which have been deprecated, as they are inherently
731      *       deadlock-prone.  See {@link Thread#suspend} for details.
732      */

733     @Deprecated(since="1.2")
734     @SuppressWarnings("deprecation")
735     public final void resume() {
736         int ngroupsSnapshot;
737         ThreadGroup[] groupsSnapshot;
738         synchronized (this) {
739             checkAccess();
740             for (int i = 0 ; i < nthreads ; i++) {
741                 threads[i].resume();
742             }
743             ngroupsSnapshot = ngroups;
744             if (groups != null) {
745                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
746             } else {
747                 groupsSnapshot = null;
748             }
749         }
750         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
751             groupsSnapshot[i].resume();
752         }
753     }
754
755     /**
756      * Destroys this thread group and all of its subgroups. This thread
757      * group must be empty, indicating that all threads that had been in
758      * this thread group have since stopped.
759      * <p>
760      * First, the {@code checkAccess} method of this thread group is
761      * called with no arguments; this may result in a security exception.
762      *
763      * @throws     IllegalThreadStateException  if the thread group is not
764      *               empty or if the thread group has already been destroyed.
765      * @throws     SecurityException  if the current thread cannot modify this
766      *               thread group.
767      * @see        java.lang.ThreadGroup#checkAccess()
768      * @since      1.0
769      */

770     public final void destroy() {
771         int ngroupsSnapshot;
772         ThreadGroup[] groupsSnapshot;
773         synchronized (this) {
774             checkAccess();
775             if (destroyed || (nthreads > 0)) {
776                 throw new IllegalThreadStateException();
777             }
778             ngroupsSnapshot = ngroups;
779             if (groups != null) {
780                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
781             } else {
782                 groupsSnapshot = null;
783             }
784             if (parent != null) {
785                 destroyed = true;
786                 ngroups = 0;
787                 groups = null;
788                 nthreads = 0;
789                 threads = null;
790             }
791         }
792         for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
793             groupsSnapshot[i].destroy();
794         }
795         if (parent != null) {
796             parent.remove(this);
797         }
798     }
799
800     /**
801      * Adds the specified Thread group to this group.
802      * @param g the specified Thread group to be added
803      * @throws  IllegalThreadStateException If the Thread group has been destroyed.
804      */

805     private final void add(ThreadGroup g){
806         synchronized (this) {
807             if (destroyed) {
808                 throw new IllegalThreadStateException();
809             }
810             if (groups == null) {
811                 groups = new ThreadGroup[4];
812             } else if (ngroups == groups.length) {
813                 groups = Arrays.copyOf(groups, ngroups * 2);
814             }
815             groups[ngroups] = g;
816
817             // This is done last so it doesn't matter in case the
818             // thread is killed
819             ngroups++;
820         }
821     }
822
823     /**
824      * Removes the specified Thread group from this group.
825      * @param g the Thread group to be removed
826      * @return if this Thread has already been destroyed.
827      */

828     private void remove(ThreadGroup g) {
829         synchronized (this) {
830             if (destroyed) {
831                 return;
832             }
833             for (int i = 0 ; i < ngroups ; i++) {
834                 if (groups[i] == g) {
835                     ngroups -= 1;
836                     System.arraycopy(groups, i + 1, groups, i, ngroups - i);
837                     // Zap dangling reference to the dead group so that
838                     // the garbage collector will collect it.
839                     groups[ngroups] = null;
840                     break;
841                 }
842             }
843             if (nthreads == 0) {
844                 notifyAll();
845             }
846             if (daemon && (nthreads == 0) &&
847                 (nUnstartedThreads == 0) && (ngroups == 0))
848             {
849                 destroy();
850             }
851         }
852     }
853
854
855     /**
856      * Increments the count of unstarted threads in the thread group.
857      * Unstarted threads are not added to the thread group so that they
858      * can be collected if they are never started, but they must be
859      * counted so that daemon thread groups with unstarted threads in
860      * them are not destroyed.
861      */

862     void addUnstarted() {
863         synchronized(this) {
864             if (destroyed) {
865                 throw new IllegalThreadStateException();
866             }
867             nUnstartedThreads++;
868         }
869     }
870
871     /**
872      * Adds the specified thread to this thread group.
873      *
874      * <p> Note: This method is called from both library code
875      * and the Virtual Machine. It is called from VM to add
876      * certain system threads to the system thread group.
877      *
878      * @param  t
879      *         the Thread to be added
880      *
881      * @throws IllegalThreadStateException
882      *          if the Thread group has been destroyed
883      */

884     void add(Thread t) {
885         synchronized (this) {
886             if (destroyed) {
887                 throw new IllegalThreadStateException();
888             }
889             if (threads == null) {
890                 threads = new Thread[4];
891             } else if (nthreads == threads.length) {
892                 threads = Arrays.copyOf(threads, nthreads * 2);
893             }
894             threads[nthreads] = t;
895
896             // This is done last so it doesn't matter in case the
897             // thread is killed
898             nthreads++;
899
900             // The thread is now a fully fledged member of the group, even
901             // though it may, or may not, have been started yet. It will prevent
902             // the group from being destroyed so the unstarted Threads count is
903             // decremented.
904             nUnstartedThreads--;
905         }
906     }
907
908     /**
909      * Notifies the group that the thread {@code t} has failed
910      * an attempt to start.
911      *
912      * <p> The state of this thread group is rolled back as if the
913      * attempt to start the thread has never occurred. The thread is again
914      * considered an unstarted member of the thread group, and a subsequent
915      * attempt to start the thread is permitted.
916      *
917      * @param  t
918      *         the Thread whose start method was invoked
919      */

920     void threadStartFailed(Thread t) {
921         synchronized(this) {
922             remove(t);
923             nUnstartedThreads++;
924         }
925     }
926
927     /**
928      * Notifies the group that the thread {@code t} has terminated.
929      *
930      * <p> Destroy the group if all of the following conditions are
931      * truethis is a daemon thread group; there are no more alive
932      * or unstarted threads in the group; there are no subgroups in
933      * this thread group.
934      *
935      * @param  t
936      *         the Thread that has terminated
937      */

938     void threadTerminated(Thread t) {
939         synchronized (this) {
940             remove(t);
941
942             if (nthreads == 0) {
943                 notifyAll();
944             }
945             if (daemon && (nthreads == 0) &&
946                 (nUnstartedThreads == 0) && (ngroups == 0))
947             {
948                 destroy();
949             }
950         }
951     }
952
953     /**
954      * Removes the specified Thread from this group. Invoking this method
955      * on a thread group that has been destroyed has no effect.
956      *
957      * @param  t
958      *         the Thread to be removed
959      */

960     private void remove(Thread t) {
961         synchronized (this) {
962             if (destroyed) {
963                 return;
964             }
965             for (int i = 0 ; i < nthreads ; i++) {
966                 if (threads[i] == t) {
967                     System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
968                     // Zap dangling reference to the dead thread so that
969                     // the garbage collector will collect it.
970                     threads[nthreads] = null;
971                     break;
972                 }
973             }
974         }
975     }
976
977     /**
978      * Prints information about this thread group to the standard
979      * output. This method is useful only for debugging.
980      *
981      * @since   1.0
982      */

983     public void list() {
984         list(System.out, 0);
985     }
986     void list(PrintStream out, int indent) {
987         int ngroupsSnapshot;
988         ThreadGroup[] groupsSnapshot;
989         synchronized (this) {
990             for (int j = 0 ; j < indent ; j++) {
991                 out.print(" ");
992             }
993             out.println(this);
994             indent += 4;
995             for (int i = 0 ; i < nthreads ; i++) {
996                 for (int j = 0 ; j < indent ; j++) {
997                     out.print(" ");
998                 }
999                 out.println(threads[i]);
1000             }
1001             ngroupsSnapshot = ngroups;
1002             if (groups != null) {
1003                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1004             } else {
1005                 groupsSnapshot = null;
1006             }
1007         }
1008         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1009             groupsSnapshot[i].list(out, indent);
1010         }
1011     }
1012
1013     /**
1014      * Called by the Java Virtual Machine when a thread in this
1015      * thread group stops because of an uncaught exception, and the thread
1016      * does not have a specific {@link Thread.UncaughtExceptionHandler}
1017      * installed.
1018      * <p>
1019      * The {@code uncaughtException} method of
1020      * {@code ThreadGroup} does the following:
1021      * <ul>
1022      * <li>If this thread group has a parent thread group, the
1023      *     {@code uncaughtException} method of that parent is called
1024      *     with the same two arguments.
1025      * <li>Otherwise, this method checks to see if there is a
1026      *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
1027      *     uncaught exception handler} installed, and if so, its
1028      *     {@code uncaughtException} method is called with the same
1029      *     two arguments.
1030      * <li>Otherwise, this method determines if the {@code Throwable}
1031      *     argument is an instance of {@link ThreadDeath}. If so, nothing
1032      *     special is done. Otherwise, a message containing the
1033      *     thread's name, as returned from the thread's {@link
1034      *     Thread#getName getName} method, and a stack backtrace,
1035      *     using the {@code Throwable}'s {@link
1036      *     Throwable#printStackTrace printStackTrace} method, is
1037      *     printed to the {@linkplain System#err standard error stream}.
1038      * </ul>
1039      * <p>
1040      * Applications can override this method in subclasses of
1041      * {@code ThreadGroup} to provide alternative handling of
1042      * uncaught exceptions.
1043      *
1044      * @param   t   the thread that is about to exit.
1045      * @param   e   the uncaught exception.
1046      * @since   1.0
1047      */

1048     public void uncaughtException(Thread t, Throwable e) {
1049         if (parent != null) {
1050             parent.uncaughtException(t, e);
1051         } else {
1052             Thread.UncaughtExceptionHandler ueh =
1053                 Thread.getDefaultUncaughtExceptionHandler();
1054             if (ueh != null) {
1055                 ueh.uncaughtException(t, e);
1056             } else if (!(e instanceof ThreadDeath)) {
1057                 System.err.print("Exception in thread \""
1058                                  + t.getName() + "\" ");
1059                 e.printStackTrace(System.err);
1060             }
1061         }
1062     }
1063
1064     /**
1065      * Used by VM to control lowmem implicit suspension.
1066      *
1067      * @param b boolean to allow or disallow suspension
1068      * @return true on success
1069      * @since   1.1
1070      * @deprecated The definition of this call depends on {@link #suspend},
1071      *             which is deprecated.  Further, the behavior of this call
1072      *             was never specified.
1073      */

1074     @Deprecated(since="1.2")
1075     public boolean allowThreadSuspension(boolean b) {
1076         return true;
1077     }
1078
1079     /**
1080      * Returns a string representation of this Thread group.
1081      *
1082      * @return  a string representation of this thread group.
1083      * @since   1.0
1084      */

1085     public String toString() {
1086         return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
1087     }
1088 }
1089