1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package java.lang;
28
29import java.io.PrintStream;
30import java.util.Arrays;
31import sun.misc.VM;
32
33/**
34 * A thread group represents a set of threads. In addition, a thread
35 * group can also include other thread groups. The thread groups form
36 * a tree in which every thread group except the initial thread group
37 * has a parent.
38 * <p>
39 * A thread is allowed to access information about its own thread
40 * group, but not to access information about its thread group's
41 * parent thread group or any other thread groups.
42 *
43 * @author  unascribed
44 * @since   JDK1.0
45 */
46/* The locking strategy for this code is to try to lock only one level of the
47 * tree wherever possible, but otherwise to lock from the bottom up.
48 * That is, from child thread groups to parents.
49 * This has the advantage of limiting the number of locks that need to be held
50 * and in particular avoids having to grab the lock for the root thread group,
51 * (or a global lock) which would be a source of contention on a
52 * multi-processor system with many thread groups.
53 * This policy often leads to taking a snapshot of the state of a thread group
54 * and working off of that snapshot, rather than holding the thread group locked
55 * while we work on the children.
56 */
57public
58class ThreadGroup implements Thread.UncaughtExceptionHandler {
59    /* the runtime uses these directly; do not rename */
60    static final ThreadGroup systemThreadGroup = new ThreadGroup();
61
62    static final ThreadGroup mainThreadGroup = new ThreadGroup(systemThreadGroup, "main");
63
64    private final ThreadGroup parent;
65    String name;
66    int maxPriority;
67    boolean destroyed;
68    boolean daemon;
69    boolean vmAllowSuspension;
70
71    int nUnstartedThreads = 0;
72    int nthreads;
73    Thread threads[];
74
75    int ngroups;
76    ThreadGroup groups[];
77
78    /**
79     * Creates an empty Thread group that is not in any Thread group.
80     * This method is used to create the system Thread group.
81     */
82    private ThreadGroup() {     // called from C code
83        this.name = "system";
84        this.maxPriority = Thread.MAX_PRIORITY;
85        this.parent = null;
86    }
87
88    /**
89     * Constructs a new thread group. The parent of this new group is
90     * the thread group of the currently running thread.
91     * <p>
92     * The <code>checkAccess</code> method of the parent thread group is
93     * called with no arguments; this may result in a security exception.
94     *
95     * @param   name   the name of the new thread group.
96     * @exception  SecurityException  if the current thread cannot create a
97     *               thread in the specified thread group.
98     * @see     java.lang.ThreadGroup#checkAccess()
99     * @since   JDK1.0
100     */
101    public ThreadGroup(String name) {
102        this(Thread.currentThread().getThreadGroup(), name);
103    }
104
105    /**
106     * Creates a new thread group. The parent of this new group is the
107     * specified thread group.
108     * <p>
109     * The <code>checkAccess</code> method of the parent thread group is
110     * called with no arguments; this may result in a security exception.
111     *
112     * @param     parent   the parent thread group.
113     * @param     name     the name of the new thread group.
114     * @exception  NullPointerException  if the thread group argument is
115     *               <code>null</code>.
116     * @exception  SecurityException  if the current thread cannot create a
117     *               thread in the specified thread group.
118     * @see     java.lang.SecurityException
119     * @see     java.lang.ThreadGroup#checkAccess()
120     * @since   JDK1.0
121     */
122    public ThreadGroup(ThreadGroup parent, String name) {
123        this(checkParentAccess(parent), parent, name);
124    }
125
126    private ThreadGroup(Void unused, ThreadGroup parent, String name) {
127        this.name = name;
128        this.maxPriority = parent.maxPriority;
129        this.daemon = parent.daemon;
130        this.vmAllowSuspension = parent.vmAllowSuspension;
131        this.parent = parent;
132        parent.add(this);
133    }
134
135    /*
136     * @throws  NullPointerException  if the parent argument is {@code null}
137     * @throws  SecurityException     if the current thread cannot create a
138     *                                thread in the specified thread group.
139     */
140    private static Void checkParentAccess(ThreadGroup parent) {
141        parent.checkAccess();
142        return null;
143    }
144
145    /**
146     * Returns the name of this thread group.
147     *
148     * @return  the name of this thread group.
149     * @since   JDK1.0
150     */
151    public final String getName() {
152        return name;
153    }
154
155    /**
156     * Returns the parent of this thread group.
157     * <p>
158     * First, if the parent is not <code>null</code>, the
159     * <code>checkAccess</code> method of the parent thread group is
160     * called with no arguments; this may result in a security exception.
161     *
162     * @return  the parent of this thread group. The top-level thread group
163     *          is the only thread group whose parent is <code>null</code>.
164     * @exception  SecurityException  if the current thread cannot modify
165     *               this thread group.
166     * @see        java.lang.ThreadGroup#checkAccess()
167     * @see        java.lang.SecurityException
168     * @see        java.lang.RuntimePermission
169     * @since   JDK1.0
170     */
171    public final ThreadGroup getParent() {
172        if (parent != null)
173            parent.checkAccess();
174        return parent;
175    }
176
177    /**
178     * Returns the maximum priority of this thread group. Threads that are
179     * part of this group cannot have a higher priority than the maximum
180     * priority.
181     *
182     * @return  the maximum priority that a thread in this thread group
183     *          can have.
184     * @see     #setMaxPriority
185     * @since   JDK1.0
186     */
187    public final int getMaxPriority() {
188        return maxPriority;
189    }
190
191    /**
192     * Tests if this thread group is a daemon thread group. A
193     * daemon thread group is automatically destroyed when its last
194     * thread is stopped or its last thread group is destroyed.
195     *
196     * @return  <code>true</code> if this thread group is a daemon thread group;
197     *          <code>false</code> otherwise.
198     * @since   JDK1.0
199     */
200    public final boolean isDaemon() {
201        return daemon;
202    }
203
204    /**
205     * Tests if this thread group has been destroyed.
206     *
207     * @return  true if this object is destroyed
208     * @since   JDK1.1
209     */
210    public synchronized boolean isDestroyed() {
211        return destroyed;
212    }
213
214    /**
215     * Changes the daemon status of this thread group.
216     * <p>
217     * First, the <code>checkAccess</code> method of this thread group is
218     * called with no arguments; this may result in a security exception.
219     * <p>
220     * A daemon thread group is automatically destroyed when its last
221     * thread is stopped or its last thread group is destroyed.
222     *
223     * @param      daemon   if <code>true</code>, marks this thread group as
224     *                      a daemon thread group; otherwise, marks this
225     *                      thread group as normal.
226     * @exception  SecurityException  if the current thread cannot modify
227     *               this thread group.
228     * @see        java.lang.SecurityException
229     * @see        java.lang.ThreadGroup#checkAccess()
230     * @since      JDK1.0
231     */
232    public final void setDaemon(boolean daemon) {
233        checkAccess();
234        this.daemon = daemon;
235    }
236
237    /**
238     * Sets the maximum priority of the group. Threads in the thread
239     * group that already have a higher priority are not affected.
240     * <p>
241     * First, the <code>checkAccess</code> method of this thread group is
242     * called with no arguments; this may result in a security exception.
243     * <p>
244     * If the <code>pri</code> argument is less than
245     * {@link Thread#MIN_PRIORITY} or greater than
246     * {@link Thread#MAX_PRIORITY}, it is clamped to those values.
247     * <p>
248     * Otherwise, the priority of this ThreadGroup object is set to the
249     * smaller of the specified <code>pri</code> and the maximum permitted
250     * priority of the parent of this thread group. (If this thread group
251     * is the system thread group, which has no parent, then its maximum
252     * priority is simply set to <code>pri</code>.) Then this method is
253     * called recursively, with <code>pri</code> as its argument, for
254     * every thread group that belongs to this thread group.
255     *
256     * @param      pri   the new priority of the thread group.
257     * @exception  SecurityException  if the current thread cannot modify
258     *               this thread group.
259     * @see        #getMaxPriority
260     * @see        java.lang.SecurityException
261     * @see        java.lang.ThreadGroup#checkAccess()
262     * @since      JDK1.0
263     */
264    // Android changed: We clamp the priority to the range [MIN_PRIORITY, MAX_PRIORITY]
265    // before using it.
266    public final void setMaxPriority(int pri) {
267        int ngroupsSnapshot;
268        ThreadGroup[] groupsSnapshot;
269        synchronized (this) {
270            checkAccess();
271            // Android changed: Clamp to MIN_PRIORITY, MAX_PRIORITY.
272            // if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
273            //     return;
274            // }
275            if (pri < Thread.MIN_PRIORITY) {
276                pri = Thread.MIN_PRIORITY;
277            }
278            if (pri > Thread.MAX_PRIORITY) {
279                pri = Thread.MAX_PRIORITY;
280            }
281
282            maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
283            ngroupsSnapshot = ngroups;
284            if (groups != null) {
285                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
286            } else {
287                groupsSnapshot = null;
288            }
289        }
290        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
291            groupsSnapshot[i].setMaxPriority(pri);
292        }
293    }
294
295    /**
296     * Tests if this thread group is either the thread group
297     * argument or one of its ancestor thread groups.
298     *
299     * @param   g   a thread group.
300     * @return  <code>true</code> if this thread group is the thread group
301     *          argument or one of its ancestor thread groups;
302     *          <code>false</code> otherwise.
303     * @since   JDK1.0
304     */
305    public final boolean parentOf(ThreadGroup g) {
306        for (; g != null ; g = g.parent) {
307            if (g == this) {
308                return true;
309            }
310        }
311        return false;
312    }
313
314    /**
315     * Determines if the currently running thread has permission to
316     * modify this thread group.
317     * <p>
318     * If there is a security manager, its <code>checkAccess</code> method
319     * is called with this thread group as its argument. This may result
320     * in throwing a <code>SecurityException</code>.
321     *
322     * @exception  SecurityException  if the current thread is not allowed to
323     *               access this thread group.
324     * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
325     * @since      JDK1.0
326     */
327    public final void checkAccess() {
328    }
329
330    /**
331     * Returns an estimate of the number of active threads in this thread
332     * group and its subgroups. Recursively iterates over all subgroups in
333     * this thread group.
334     *
335     * <p> The value returned is only an estimate because the number of
336     * threads may change dynamically while this method traverses internal
337     * data structures, and might be affected by the presence of certain
338     * system threads. This method is intended primarily for debugging
339     * and monitoring purposes.
340     *
341     * @return  an estimate of the number of active threads in this thread
342     *          group and in any other thread group that has this thread
343     *          group as an ancestor
344     *
345     * @since   JDK1.0
346     */
347    public int activeCount() {
348        int result;
349        // Snapshot sub-group data so we don't hold this lock
350        // while our children are computing.
351        int ngroupsSnapshot;
352        ThreadGroup[] groupsSnapshot;
353        synchronized (this) {
354            if (destroyed) {
355                return 0;
356            }
357            result = nthreads;
358            ngroupsSnapshot = ngroups;
359            if (groups != null) {
360                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
361            } else {
362                groupsSnapshot = null;
363            }
364        }
365        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
366            result += groupsSnapshot[i].activeCount();
367        }
368        return result;
369    }
370
371    /**
372     * Copies into the specified array every active thread in this
373     * thread group and its subgroups.
374     *
375     * <p> An invocation of this method behaves in exactly the same
376     * way as the invocation
377     *
378     * <blockquote>
379     * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}
380     * </blockquote>
381     *
382     * @param  list
383     *         an array into which to put the list of threads
384     *
385     * @return  the number of threads put into the array
386     *
387     * @throws  SecurityException
388     *          if {@linkplain #checkAccess checkAccess} determines that
389     *          the current thread cannot access this thread group
390     *
391     * @since   JDK1.0
392     */
393    public int enumerate(Thread list[]) {
394        checkAccess();
395        return enumerate(list, 0, true);
396    }
397
398    /**
399     * Copies into the specified array every active thread in this
400     * thread group. If {@code recurse} is {@code true},
401     * this method recursively enumerates all subgroups of this
402     * thread group and references to every active thread in these
403     * subgroups are also included. If the array is too short to
404     * hold all the threads, the extra threads are silently ignored.
405     *
406     * <p> An application might use the {@linkplain #activeCount activeCount}
407     * method to get an estimate of how big the array should be, however
408     * <i>if the array is too short to hold all the threads, the extra threads
409     * are silently ignored.</i>  If it is critical to obtain every active
410     * thread in this thread group, the caller should verify that the returned
411     * int value is strictly less than the length of {@code list}.
412     *
413     * <p> Due to the inherent race condition in this method, it is recommended
414     * that the method only be used for debugging and monitoring purposes.
415     *
416     * @param  list
417     *         an array into which to put the list of threads
418     *
419     * @param  recurse
420     *         if {@code true}, recursively enumerate all subgroups of this
421     *         thread group
422     *
423     * @return  the number of threads put into the array
424     *
425     * @throws  SecurityException
426     *          if {@linkplain #checkAccess checkAccess} determines that
427     *          the current thread cannot access this thread group
428     *
429     * @since   JDK1.0
430     */
431    public int enumerate(Thread list[], boolean recurse) {
432        checkAccess();
433        return enumerate(list, 0, recurse);
434    }
435
436    private int enumerate(Thread list[], int n, boolean recurse) {
437        int ngroupsSnapshot = 0;
438        ThreadGroup[] groupsSnapshot = null;
439        synchronized (this) {
440            if (destroyed) {
441                return 0;
442            }
443            int nt = nthreads;
444            if (nt > list.length - n) {
445                nt = list.length - n;
446            }
447            for (int i = 0; i < nt; i++) {
448                if (threads[i].isAlive()) {
449                    list[n++] = threads[i];
450                }
451            }
452            if (recurse) {
453                ngroupsSnapshot = ngroups;
454                if (groups != null) {
455                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
456                } else {
457                    groupsSnapshot = null;
458                }
459            }
460        }
461        if (recurse) {
462            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
463                n = groupsSnapshot[i].enumerate(list, n, true);
464            }
465        }
466        return n;
467    }
468
469    /**
470     * Returns an estimate of the number of active groups in this
471     * thread group and its subgroups. Recursively iterates over
472     * all subgroups in this thread group.
473     *
474     * <p> The value returned is only an estimate because the number of
475     * thread groups may change dynamically while this method traverses
476     * internal data structures. This method is intended primarily for
477     * debugging and monitoring purposes.
478     *
479     * @return  the number of active thread groups with this thread group as
480     *          an ancestor
481     *
482     * @since   JDK1.0
483     */
484    public int activeGroupCount() {
485        int ngroupsSnapshot;
486        ThreadGroup[] groupsSnapshot;
487        synchronized (this) {
488            if (destroyed) {
489                return 0;
490            }
491            ngroupsSnapshot = ngroups;
492            if (groups != null) {
493                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
494            } else {
495                groupsSnapshot = null;
496            }
497        }
498        int n = ngroupsSnapshot;
499        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
500            n += groupsSnapshot[i].activeGroupCount();
501        }
502        return n;
503    }
504
505    /**
506     * Copies into the specified array references to every active
507     * subgroup in this thread group and its subgroups.
508     *
509     * <p> An invocation of this method behaves in exactly the same
510     * way as the invocation
511     *
512     * <blockquote>
513     * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)}
514     * </blockquote>
515     *
516     * @param  list
517     *         an array into which to put the list of thread groups
518     *
519     * @return  the number of thread groups put into the array
520     *
521     * @throws  SecurityException
522     *          if {@linkplain #checkAccess checkAccess} determines that
523     *          the current thread cannot access this thread group
524     *
525     * @since   JDK1.0
526     */
527    public int enumerate(ThreadGroup list[]) {
528        checkAccess();
529        return enumerate(list, 0, true);
530    }
531
532    /**
533     * Copies into the specified array references to every active
534     * subgroup in this thread group. If {@code recurse} is
535     * {@code true}, this method recursively enumerates all subgroups of this
536     * thread group and references to every active thread group in these
537     * subgroups are also included.
538     *
539     * <p> An application might use the
540     * {@linkplain #activeGroupCount activeGroupCount} method to
541     * get an estimate of how big the array should be, however <i>if the
542     * array is too short to hold all the thread groups, the extra thread
543     * groups are silently ignored.</i>  If it is critical to obtain every
544     * active subgroup in this thread group, the caller should verify that
545     * the returned int value is strictly less than the length of
546     * {@code list}.
547     *
548     * <p> Due to the inherent race condition in this method, it is recommended
549     * that the method only be used for debugging and monitoring purposes.
550     *
551     * @param  list
552     *         an array into which to put the list of thread groups
553     *
554     * @param  recurse
555     *         if {@code true}, recursively enumerate all subgroups
556     *
557     * @return  the number of thread groups put into the array
558     *
559     * @throws  SecurityException
560     *          if {@linkplain #checkAccess checkAccess} determines that
561     *          the current thread cannot access this thread group
562     *
563     * @since   JDK1.0
564     */
565    public int enumerate(ThreadGroup list[], boolean recurse) {
566        checkAccess();
567        return enumerate(list, 0, recurse);
568    }
569
570    private int enumerate(ThreadGroup list[], int n, boolean recurse) {
571        int ngroupsSnapshot = 0;
572        ThreadGroup[] groupsSnapshot = null;
573        synchronized (this) {
574            if (destroyed) {
575                return 0;
576            }
577            int ng = ngroups;
578            if (ng > list.length - n) {
579                ng = list.length - n;
580            }
581            if (ng > 0) {
582                System.arraycopy(groups, 0, list, n, ng);
583                n += ng;
584            }
585            if (recurse) {
586                ngroupsSnapshot = ngroups;
587                if (groups != null) {
588                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
589                } else {
590                    groupsSnapshot = null;
591                }
592            }
593        }
594        if (recurse) {
595            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
596                n = groupsSnapshot[i].enumerate(list, n, true);
597            }
598        }
599        return n;
600    }
601
602    /**
603     * Stops all threads in this thread group.
604     * <p>
605     * First, the <code>checkAccess</code> method of this thread group is
606     * called with no arguments; this may result in a security exception.
607     * <p>
608     * This method then calls the <code>stop</code> method on all the
609     * threads in this thread group and in all of its subgroups.
610     *
611     * @exception  SecurityException  if the current thread is not allowed
612     *               to access this thread group or any of the threads in
613     *               the thread group.
614     * @see        java.lang.SecurityException
615     * @see        java.lang.Thread#stop()
616     * @see        java.lang.ThreadGroup#checkAccess()
617     * @since      JDK1.0
618     * @deprecated    This method is inherently unsafe.  See
619     *     {@link Thread#stop} for details.
620     */
621    @Deprecated
622    public final void stop() {
623        if (stopOrSuspend(false))
624            Thread.currentThread().stop();
625    }
626
627    /**
628     * Interrupts all threads in this thread group.
629     * <p>
630     * First, the <code>checkAccess</code> method of this thread group is
631     * called with no arguments; this may result in a security exception.
632     * <p>
633     * This method then calls the <code>interrupt</code> method on all the
634     * threads in this thread group and in all of its subgroups.
635     *
636     * @exception  SecurityException  if the current thread is not allowed
637     *               to access this thread group or any of the threads in
638     *               the thread group.
639     * @see        java.lang.Thread#interrupt()
640     * @see        java.lang.SecurityException
641     * @see        java.lang.ThreadGroup#checkAccess()
642     * @since      1.2
643     */
644    public final void interrupt() {
645        int ngroupsSnapshot;
646        ThreadGroup[] groupsSnapshot;
647        synchronized (this) {
648            checkAccess();
649            for (int i = 0 ; i < nthreads ; i++) {
650                threads[i].interrupt();
651            }
652            ngroupsSnapshot = ngroups;
653            if (groups != null) {
654                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
655            } else {
656                groupsSnapshot = null;
657            }
658        }
659        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
660            groupsSnapshot[i].interrupt();
661        }
662    }
663
664    /**
665     * Suspends all threads in this thread group.
666     * <p>
667     * First, the <code>checkAccess</code> method of this thread group is
668     * called with no arguments; this may result in a security exception.
669     * <p>
670     * This method then calls the <code>suspend</code> method on all the
671     * threads in this thread group and in all of its subgroups.
672     *
673     * @exception  SecurityException  if the current thread is not allowed
674     *               to access this thread group or any of the threads in
675     *               the thread group.
676     * @see        java.lang.Thread#suspend()
677     * @see        java.lang.SecurityException
678     * @see        java.lang.ThreadGroup#checkAccess()
679     * @since      JDK1.0
680     * @deprecated    This method is inherently deadlock-prone.  See
681     *     {@link Thread#suspend} for details.
682     */
683    @Deprecated
684    public final void suspend() {
685        if (stopOrSuspend(true))
686            Thread.currentThread().suspend();
687    }
688
689    /**
690     * Helper method: recursively stops or suspends (as directed by the
691     * boolean argument) all of the threads in this thread group and its
692     * subgroups, except the current thread.  This method returns true
693     * if (and only if) the current thread is found to be in this thread
694     * group or one of its subgroups.
695     */
696    private boolean stopOrSuspend(boolean suspend) {
697        boolean suicide = false;
698        Thread us = Thread.currentThread();
699        int ngroupsSnapshot;
700        ThreadGroup[] groupsSnapshot = null;
701        synchronized (this) {
702            checkAccess();
703            for (int i = 0 ; i < nthreads ; i++) {
704                if (threads[i]==us)
705                    suicide = true;
706                else if (suspend)
707                    threads[i].suspend();
708                else
709                    threads[i].stop();
710            }
711
712            ngroupsSnapshot = ngroups;
713            if (groups != null) {
714                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
715            }
716        }
717        for (int i = 0 ; i < ngroupsSnapshot ; i++)
718            suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
719
720        return suicide;
721    }
722
723    /**
724     * Resumes all threads in this thread group.
725     * <p>
726     * First, the <code>checkAccess</code> method of this thread group is
727     * called with no arguments; this may result in a security exception.
728     * <p>
729     * This method then calls the <code>resume</code> method on all the
730     * threads in this thread group and in all of its sub groups.
731     *
732     * @exception  SecurityException  if the current thread is not allowed to
733     *               access this thread group or any of the threads in the
734     *               thread group.
735     * @see        java.lang.SecurityException
736     * @see        java.lang.Thread#resume()
737     * @see        java.lang.ThreadGroup#checkAccess()
738     * @since      JDK1.0
739     * @deprecated    This method is used solely in conjunction with
740     *      <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
741     *       both of which have been deprecated, as they are inherently
742     *       deadlock-prone.  See {@link Thread#suspend} for details.
743     */
744    @Deprecated
745    public final void resume() {
746        int ngroupsSnapshot;
747        ThreadGroup[] groupsSnapshot;
748        synchronized (this) {
749            checkAccess();
750            for (int i = 0 ; i < nthreads ; i++) {
751                threads[i].resume();
752            }
753            ngroupsSnapshot = ngroups;
754            if (groups != null) {
755                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
756            } else {
757                groupsSnapshot = null;
758            }
759        }
760        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
761            groupsSnapshot[i].resume();
762        }
763    }
764
765    /**
766     * Destroys this thread group and all of its subgroups. This thread
767     * group must be empty, indicating that all threads that had been in
768     * this thread group have since stopped.
769     * <p>
770     * First, the <code>checkAccess</code> method of this thread group is
771     * called with no arguments; this may result in a security exception.
772     *
773     * @exception  IllegalThreadStateException  if the thread group is not
774     *               empty or if the thread group has already been destroyed.
775     * @exception  SecurityException  if the current thread cannot modify this
776     *               thread group.
777     * @see        java.lang.ThreadGroup#checkAccess()
778     * @since      JDK1.0
779     */
780    public final void destroy() {
781        int ngroupsSnapshot;
782        ThreadGroup[] groupsSnapshot;
783        synchronized (this) {
784            checkAccess();
785            if (destroyed || (nthreads > 0)) {
786                throw new IllegalThreadStateException();
787            }
788            ngroupsSnapshot = ngroups;
789            if (groups != null) {
790                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
791            } else {
792                groupsSnapshot = null;
793            }
794            if (parent != null) {
795                destroyed = true;
796                ngroups = 0;
797                groups = null;
798                nthreads = 0;
799                threads = null;
800            }
801        }
802        for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
803            groupsSnapshot[i].destroy();
804        }
805        if (parent != null) {
806            parent.remove(this);
807        }
808    }
809
810    /**
811     * Adds the specified Thread group to this group.
812     * @param g the specified Thread group to be added
813     * @exception IllegalThreadStateException If the Thread group has been destroyed.
814     */
815    private final void add(ThreadGroup g){
816        synchronized (this) {
817            if (destroyed) {
818                throw new IllegalThreadStateException();
819            }
820            if (groups == null) {
821                groups = new ThreadGroup[4];
822            } else if (ngroups == groups.length) {
823                groups = Arrays.copyOf(groups, ngroups * 2);
824            }
825            groups[ngroups] = g;
826
827            // This is done last so it doesn't matter in case the
828            // thread is killed
829            ngroups++;
830        }
831    }
832
833    /**
834     * Removes the specified Thread group from this group.
835     * @param g the Thread group to be removed
836     * @return if this Thread has already been destroyed.
837     */
838    private void remove(ThreadGroup g) {
839        synchronized (this) {
840            if (destroyed) {
841                return;
842            }
843            for (int i = 0 ; i < ngroups ; i++) {
844                if (groups[i] == g) {
845                    ngroups -= 1;
846                    System.arraycopy(groups, i + 1, groups, i, ngroups - i);
847                    // Zap dangling reference to the dead group so that
848                    // the garbage collector will collect it.
849                    groups[ngroups] = null;
850                    break;
851                }
852            }
853            if (nthreads == 0) {
854                notifyAll();
855            }
856            if (daemon && (nthreads == 0) &&
857                (nUnstartedThreads == 0) && (ngroups == 0))
858            {
859                destroy();
860            }
861        }
862    }
863
864
865    /**
866     * Increments the count of unstarted threads in the thread group.
867     * Unstarted threads are not added to the thread group so that they
868     * can be collected if they are never started, but they must be
869     * counted so that daemon thread groups with unstarted threads in
870     * them are not destroyed.
871     */
872    void addUnstarted() {
873        synchronized(this) {
874            if (destroyed) {
875                throw new IllegalThreadStateException();
876            }
877            nUnstartedThreads++;
878        }
879    }
880
881    /**
882     * Adds the specified thread to this thread group.
883     *
884     * <p> Note: This method is called from both library code
885     * and the Virtual Machine. It is called from VM to add
886     * certain system threads to the system thread group.
887     *
888     * @param  t
889     *         the Thread to be added
890     *
891     * @throws  IllegalThreadStateException
892     *          if the Thread group has been destroyed
893     */
894    void add(Thread t) {
895        synchronized (this) {
896            if (destroyed) {
897                throw new IllegalThreadStateException();
898            }
899            if (threads == null) {
900                threads = new Thread[4];
901            } else if (nthreads == threads.length) {
902                threads = Arrays.copyOf(threads, nthreads * 2);
903            }
904            threads[nthreads] = t;
905
906            // This is done last so it doesn't matter in case the
907            // thread is killed
908            nthreads++;
909
910            // The thread is now a fully fledged member of the group, even
911            // though it may, or may not, have been started yet. It will prevent
912            // the group from being destroyed so the unstarted Threads count is
913            // decremented.
914            nUnstartedThreads--;
915        }
916    }
917
918    /**
919     * Notifies the group that the thread {@code t} has failed
920     * an attempt to start.
921     *
922     * <p> The state of this thread group is rolled back as if the
923     * attempt to start the thread has never occurred. The thread is again
924     * considered an unstarted member of the thread group, and a subsequent
925     * attempt to start the thread is permitted.
926     *
927     * @param  t
928     *         the Thread whose start method was invoked
929     *
930     * @param  failed
931     *         true if the thread could not be started successfully
932     */
933    void threadStartFailed(Thread t) {
934        synchronized(this) {
935            remove(t);
936            nUnstartedThreads++;
937        }
938    }
939
940    /**
941     * Notifies the group that the thread {@code t} has terminated.
942     *
943     * <p> Destroy the group if all of the following conditions are
944     * true: this is a daemon thread group; there are no more alive
945     * or unstarted threads in the group; there are no subgroups in
946     * this thread group.
947     *
948     * @param  t
949     *         the Thread that has terminated
950     */
951    void threadTerminated(Thread t) {
952        synchronized (this) {
953            remove(t);
954
955            if (nthreads == 0) {
956                notifyAll();
957            }
958            if (daemon && (nthreads == 0) &&
959                (nUnstartedThreads == 0) && (ngroups == 0))
960            {
961                destroy();
962            }
963        }
964    }
965
966    /**
967     * Removes the specified Thread from this group. Invoking this method
968     * on a thread group that has been destroyed has no effect.
969     *
970     * @param  t
971     *         the Thread to be removed
972     */
973    private void remove(Thread t) {
974        synchronized (this) {
975            if (destroyed) {
976                return;
977            }
978            for (int i = 0 ; i < nthreads ; i++) {
979                if (threads[i] == t) {
980                    System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
981                    // Zap dangling reference to the dead thread so that
982                    // the garbage collector will collect it.
983                    threads[nthreads] = null;
984                    break;
985                }
986            }
987        }
988    }
989
990    /**
991     * Prints information about this thread group to the standard
992     * output. This method is useful only for debugging.
993     *
994     * @since   JDK1.0
995     */
996    public void list() {
997        list(System.out, 0);
998    }
999    void list(PrintStream out, int indent) {
1000        int ngroupsSnapshot;
1001        ThreadGroup[] groupsSnapshot;
1002        synchronized (this) {
1003            for (int j = 0 ; j < indent ; j++) {
1004                out.print(" ");
1005            }
1006            out.println(this);
1007            indent += 4;
1008            for (int i = 0 ; i < nthreads ; i++) {
1009                for (int j = 0 ; j < indent ; j++) {
1010                    out.print(" ");
1011                }
1012                out.println(threads[i]);
1013            }
1014            ngroupsSnapshot = ngroups;
1015            if (groups != null) {
1016                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1017            } else {
1018                groupsSnapshot = null;
1019            }
1020        }
1021        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1022            groupsSnapshot[i].list(out, indent);
1023        }
1024    }
1025
1026    /**
1027     * Called by the Java Virtual Machine when a thread in this
1028     * thread group stops because of an uncaught exception, and the thread
1029     * does not have a specific {@link Thread.UncaughtExceptionHandler}
1030     * installed.
1031     * <p>
1032     * The <code>uncaughtException</code> method of
1033     * <code>ThreadGroup</code> does the following:
1034     * <ul>
1035     * <li>If this thread group has a parent thread group, the
1036     *     <code>uncaughtException</code> method of that parent is called
1037     *     with the same two arguments.
1038     * <li>Otherwise, this method checks to see if there is a
1039     *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
1040     *     uncaught exception handler} installed, and if so, its
1041     *     <code>uncaughtException</code> method is called with the same
1042     *     two arguments.
1043     * <li>Otherwise, this method determines if the <code>Throwable</code>
1044     *     argument is an instance of {@link ThreadDeath}. If so, nothing
1045     *     special is done. Otherwise, a message containing the
1046     *     thread's name, as returned from the thread's {@link
1047     *     Thread#getName getName} method, and a stack backtrace,
1048     *     using the <code>Throwable</code>'s {@link
1049     *     Throwable#printStackTrace printStackTrace} method, is
1050     *     printed to the {@linkplain System#err standard error stream}.
1051     * </ul>
1052     * <p>
1053     * Applications can override this method in subclasses of
1054     * <code>ThreadGroup</code> to provide alternative handling of
1055     * uncaught exceptions.
1056     *
1057     * @param   t   the thread that is about to exit.
1058     * @param   e   the uncaught exception.
1059     * @since   JDK1.0
1060     */
1061    public void uncaughtException(Thread t, Throwable e) {
1062        if (parent != null) {
1063            parent.uncaughtException(t, e);
1064        } else {
1065            Thread.UncaughtExceptionHandler ueh =
1066                Thread.getDefaultUncaughtExceptionHandler();
1067            if (ueh != null) {
1068                ueh.uncaughtException(t, e);
1069            } else if (!(e instanceof ThreadDeath)) {
1070                System.err.print("Exception in thread \""
1071                                 + t.getName() + "\" ");
1072                e.printStackTrace(System.err);
1073            }
1074        }
1075    }
1076
1077    /**
1078     * Used by VM to control lowmem implicit suspension.
1079     *
1080     * @param b boolean to allow or disallow suspension
1081     * @return true on success
1082     * @since   JDK1.1
1083     * @deprecated The definition of this call depends on {@link #suspend},
1084     *             which is deprecated.  Further, the behavior of this call
1085     *             was never specified.
1086     */
1087    @Deprecated
1088    public boolean allowThreadSuspension(boolean b) {
1089        this.vmAllowSuspension = b;
1090        if (!b) {
1091            VM.unsuspendSomeThreads();
1092        }
1093        return true;
1094    }
1095
1096    /**
1097     * Returns a string representation of this Thread group.
1098     *
1099     * @return  a string representation of this thread group.
1100     * @since   JDK1.0
1101     */
1102    public String toString() {
1103        return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
1104    }
1105}
1106