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
26package java.lang;
27
28import java.io.PrintStream;
29import java.util.Arrays;
30import 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 */
56public
57class 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</code> 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     * @exception  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</code> 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     * @exception  NullPointerException  if the thread group argument is
108     *               <code>null</code>.
109     * @exception  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</code>, the
151     * <code>checkAccess</code> 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</code>.
156     * @exception  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>true</code> if this thread group is a daemon thread group;
189     *          <code>false</code> 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</code> 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</code>, marks this thread group as
216     *                      a daemon thread group; otherwise, marks this
217     *                      thread group as normal.
218     * @exception  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</code> 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</code> 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</code> 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</code>.) Then this method is
246     * called recursively, with <code>pri</code> 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     * @exception  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>true</code> if this thread group is the thread group
284     *          argument or one of its ancestor thread groups;
285     *          <code>false</code> 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</code> method
302     * is called with this thread group as its argument. This may result
303     * in throwing a <code>SecurityException</code>.
304     *
305     * @exception  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</code> 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</code> method on all the
596     * threads in this thread group and in all of its subgroups.
597     *
598     * @exception  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</code> 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</code> method on all the
621     * threads in this thread group and in all of its subgroups.
622     *
623     * @exception  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</code> 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</code> method on all the
658     * threads in this thread group and in all of its subgroups.
659     *
660     * @exception  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</code> 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</code> method on all the
719     * threads in this thread group and in all of its sub groups.
720     *
721     * @exception  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</code> method of this thread group is
761     * called with no arguments; this may result in a security exception.
762     *
763     * @exception  IllegalThreadStateException  if the thread group is not
764     *               empty or if the thread group has already been destroyed.
765     * @exception  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     * @exception 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     * true: this 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</code> method of
1020     * <code>ThreadGroup</code> does the following:
1021     * <ul>
1022     * <li>If this thread group has a parent thread group, the
1023     *     <code>uncaughtException</code> 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</code> method is called with the same
1029     *     two arguments.
1030     * <li>Otherwise, this method determines if the <code>Throwable</code>
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</code>'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</code> 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