• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1995, 2012, 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 
27 package java.lang;
28 
29 import java.io.PrintStream;
30 import java.util.Arrays;
31 import 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  */
57 public
58 class 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      */
ThreadGroup()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      */
ThreadGroup(String name)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      */
ThreadGroup(ThreadGroup parent, String name)122     public ThreadGroup(ThreadGroup parent, String name) {
123         this(checkParentAccess(parent), parent, name);
124     }
125 
ThreadGroup(Void unused, ThreadGroup parent, String name)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      */
checkParentAccess(ThreadGroup parent)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      */
getName()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      */
getParent()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      */
getMaxPriority()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      */
isDaemon()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      */
isDestroyed()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      */
setDaemon(boolean daemon)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      */
setMaxPriority(int pri)264     public final void setMaxPriority(int pri) {
265         int ngroupsSnapshot;
266         ThreadGroup[] groupsSnapshot;
267         synchronized (this) {
268             checkAccess();
269             // BEGIN Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY].
270             // This preserves backward compatibility with previous versions of Android.
271             // if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
272             //     return;
273             // }
274             if (pri < Thread.MIN_PRIORITY) {
275                 pri = Thread.MIN_PRIORITY;
276             }
277             if (pri > Thread.MAX_PRIORITY) {
278                 pri = Thread.MAX_PRIORITY;
279             }
280             // END Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY].
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      */
parentOf(ThreadGroup g)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      */
checkAccess()327     public final void checkAccess() {
328         // Android-removed: SecurityManager stubbed out on Android.
329         // SecurityManager security = System.getSecurityManager();
330         // if (security != null) {
331         //     security.checkAccess(this);
332         // }
333     }
334 
335     /**
336      * Returns an estimate of the number of active threads in this thread
337      * group and its subgroups. Recursively iterates over all subgroups in
338      * this thread group.
339      *
340      * <p> The value returned is only an estimate because the number of
341      * threads may change dynamically while this method traverses internal
342      * data structures, and might be affected by the presence of certain
343      * system threads. This method is intended primarily for debugging
344      * and monitoring purposes.
345      *
346      * @return  an estimate of the number of active threads in this thread
347      *          group and in any other thread group that has this thread
348      *          group as an ancestor
349      *
350      * @since   JDK1.0
351      */
activeCount()352     public int activeCount() {
353         int result;
354         // Snapshot sub-group data so we don't hold this lock
355         // while our children are computing.
356         int ngroupsSnapshot;
357         ThreadGroup[] groupsSnapshot;
358         synchronized (this) {
359             if (destroyed) {
360                 return 0;
361             }
362             result = nthreads;
363             ngroupsSnapshot = ngroups;
364             if (groups != null) {
365                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
366             } else {
367                 groupsSnapshot = null;
368             }
369         }
370         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
371             result += groupsSnapshot[i].activeCount();
372         }
373         return result;
374     }
375 
376     /**
377      * Copies into the specified array every active thread in this
378      * thread group and its subgroups.
379      *
380      * <p> An invocation of this method behaves in exactly the same
381      * way as the invocation
382      *
383      * <blockquote>
384      * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}
385      * </blockquote>
386      *
387      * @param  list
388      *         an array into which to put the list of threads
389      *
390      * @return  the number of threads put into the array
391      *
392      * @throws  SecurityException
393      *          if {@linkplain #checkAccess checkAccess} determines that
394      *          the current thread cannot access this thread group
395      *
396      * @since   JDK1.0
397      */
enumerate(Thread list[])398     public int enumerate(Thread list[]) {
399         checkAccess();
400         return enumerate(list, 0, true);
401     }
402 
403     /**
404      * Copies into the specified array every active thread in this
405      * thread group. If {@code recurse} is {@code true},
406      * this method recursively enumerates all subgroups of this
407      * thread group and references to every active thread in these
408      * subgroups are also included. If the array is too short to
409      * hold all the threads, the extra threads are silently ignored.
410      *
411      * <p> An application might use the {@linkplain #activeCount activeCount}
412      * method to get an estimate of how big the array should be, however
413      * <i>if the array is too short to hold all the threads, the extra threads
414      * are silently ignored.</i>  If it is critical to obtain every active
415      * thread in this thread group, the caller should verify that the returned
416      * int value is strictly less than the length of {@code list}.
417      *
418      * <p> Due to the inherent race condition in this method, it is recommended
419      * that the method only be used for debugging and monitoring purposes.
420      *
421      * @param  list
422      *         an array into which to put the list of threads
423      *
424      * @param  recurse
425      *         if {@code true}, recursively enumerate all subgroups of this
426      *         thread group
427      *
428      * @return  the number of threads put into the array
429      *
430      * @throws  SecurityException
431      *          if {@linkplain #checkAccess checkAccess} determines that
432      *          the current thread cannot access this thread group
433      *
434      * @since   JDK1.0
435      */
enumerate(Thread list[], boolean recurse)436     public int enumerate(Thread list[], boolean recurse) {
437         checkAccess();
438         return enumerate(list, 0, recurse);
439     }
440 
enumerate(Thread list[], int n, boolean recurse)441     private int enumerate(Thread list[], int n, boolean recurse) {
442         int ngroupsSnapshot = 0;
443         ThreadGroup[] groupsSnapshot = null;
444         synchronized (this) {
445             if (destroyed) {
446                 return 0;
447             }
448             int nt = nthreads;
449             if (nt > list.length - n) {
450                 nt = list.length - n;
451             }
452             for (int i = 0; i < nt; i++) {
453                 if (threads[i].isAlive()) {
454                     list[n++] = threads[i];
455                 }
456             }
457             if (recurse) {
458                 ngroupsSnapshot = ngroups;
459                 if (groups != null) {
460                     groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
461                 } else {
462                     groupsSnapshot = null;
463                 }
464             }
465         }
466         if (recurse) {
467             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
468                 n = groupsSnapshot[i].enumerate(list, n, true);
469             }
470         }
471         return n;
472     }
473 
474     /**
475      * Returns an estimate of the number of active groups in this
476      * thread group and its subgroups. Recursively iterates over
477      * all subgroups in this thread group.
478      *
479      * <p> The value returned is only an estimate because the number of
480      * thread groups may change dynamically while this method traverses
481      * internal data structures. This method is intended primarily for
482      * debugging and monitoring purposes.
483      *
484      * @return  the number of active thread groups with this thread group as
485      *          an ancestor
486      *
487      * @since   JDK1.0
488      */
activeGroupCount()489     public int activeGroupCount() {
490         int ngroupsSnapshot;
491         ThreadGroup[] groupsSnapshot;
492         synchronized (this) {
493             if (destroyed) {
494                 return 0;
495             }
496             ngroupsSnapshot = ngroups;
497             if (groups != null) {
498                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
499             } else {
500                 groupsSnapshot = null;
501             }
502         }
503         int n = ngroupsSnapshot;
504         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
505             n += groupsSnapshot[i].activeGroupCount();
506         }
507         return n;
508     }
509 
510     /**
511      * Copies into the specified array references to every active
512      * subgroup in this thread group and its subgroups.
513      *
514      * <p> An invocation of this method behaves in exactly the same
515      * way as the invocation
516      *
517      * <blockquote>
518      * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)}
519      * </blockquote>
520      *
521      * @param  list
522      *         an array into which to put the list of thread groups
523      *
524      * @return  the number of thread groups put into the array
525      *
526      * @throws  SecurityException
527      *          if {@linkplain #checkAccess checkAccess} determines that
528      *          the current thread cannot access this thread group
529      *
530      * @since   JDK1.0
531      */
enumerate(ThreadGroup list[])532     public int enumerate(ThreadGroup list[]) {
533         checkAccess();
534         return enumerate(list, 0, true);
535     }
536 
537     /**
538      * Copies into the specified array references to every active
539      * subgroup in this thread group. If {@code recurse} is
540      * {@code true}, this method recursively enumerates all subgroups of this
541      * thread group and references to every active thread group in these
542      * subgroups are also included.
543      *
544      * <p> An application might use the
545      * {@linkplain #activeGroupCount activeGroupCount} method to
546      * get an estimate of how big the array should be, however <i>if the
547      * array is too short to hold all the thread groups, the extra thread
548      * groups are silently ignored.</i>  If it is critical to obtain every
549      * active subgroup in this thread group, the caller should verify that
550      * the returned int value is strictly less than the length of
551      * {@code list}.
552      *
553      * <p> Due to the inherent race condition in this method, it is recommended
554      * that the method only be used for debugging and monitoring purposes.
555      *
556      * @param  list
557      *         an array into which to put the list of thread groups
558      *
559      * @param  recurse
560      *         if {@code true}, recursively enumerate all subgroups
561      *
562      * @return  the number of thread groups put into the array
563      *
564      * @throws  SecurityException
565      *          if {@linkplain #checkAccess checkAccess} determines that
566      *          the current thread cannot access this thread group
567      *
568      * @since   JDK1.0
569      */
enumerate(ThreadGroup list[], boolean recurse)570     public int enumerate(ThreadGroup list[], boolean recurse) {
571         checkAccess();
572         return enumerate(list, 0, recurse);
573     }
574 
enumerate(ThreadGroup list[], int n, boolean recurse)575     private int enumerate(ThreadGroup list[], int n, boolean recurse) {
576         int ngroupsSnapshot = 0;
577         ThreadGroup[] groupsSnapshot = null;
578         synchronized (this) {
579             if (destroyed) {
580                 return 0;
581             }
582             int ng = ngroups;
583             if (ng > list.length - n) {
584                 ng = list.length - n;
585             }
586             if (ng > 0) {
587                 System.arraycopy(groups, 0, list, n, ng);
588                 n += ng;
589             }
590             if (recurse) {
591                 ngroupsSnapshot = ngroups;
592                 if (groups != null) {
593                     groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
594                 } else {
595                     groupsSnapshot = null;
596                 }
597             }
598         }
599         if (recurse) {
600             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
601                 n = groupsSnapshot[i].enumerate(list, n, true);
602             }
603         }
604         return n;
605     }
606 
607     /**
608      * Stops all threads in this thread group.
609      * <p>
610      * First, the <code>checkAccess</code> method of this thread group is
611      * called with no arguments; this may result in a security exception.
612      * <p>
613      * This method then calls the <code>stop</code> method on all the
614      * threads in this thread group and in all of its subgroups.
615      *
616      * @exception  SecurityException  if the current thread is not allowed
617      *               to access this thread group or any of the threads in
618      *               the thread group.
619      * @see        java.lang.SecurityException
620      * @see        java.lang.Thread#stop()
621      * @see        java.lang.ThreadGroup#checkAccess()
622      * @since      JDK1.0
623      * @deprecated    This method is inherently unsafe.  See
624      *     {@link Thread#stop} for details.
625      */
626     @Deprecated
stop()627     public final void stop() {
628         if (stopOrSuspend(false))
629             Thread.currentThread().stop();
630     }
631 
632     /**
633      * Interrupts all threads in this thread group.
634      * <p>
635      * First, the <code>checkAccess</code> method of this thread group is
636      * called with no arguments; this may result in a security exception.
637      * <p>
638      * This method then calls the <code>interrupt</code> method on all the
639      * threads in this thread group and in all of its subgroups.
640      *
641      * @exception  SecurityException  if the current thread is not allowed
642      *               to access this thread group or any of the threads in
643      *               the thread group.
644      * @see        java.lang.Thread#interrupt()
645      * @see        java.lang.SecurityException
646      * @see        java.lang.ThreadGroup#checkAccess()
647      * @since      1.2
648      */
interrupt()649     public final void interrupt() {
650         int ngroupsSnapshot;
651         ThreadGroup[] groupsSnapshot;
652         synchronized (this) {
653             checkAccess();
654             for (int i = 0 ; i < nthreads ; i++) {
655                 threads[i].interrupt();
656             }
657             ngroupsSnapshot = ngroups;
658             if (groups != null) {
659                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
660             } else {
661                 groupsSnapshot = null;
662             }
663         }
664         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
665             groupsSnapshot[i].interrupt();
666         }
667     }
668 
669     /**
670      * Suspends all threads in this thread group.
671      * <p>
672      * First, the <code>checkAccess</code> method of this thread group is
673      * called with no arguments; this may result in a security exception.
674      * <p>
675      * This method then calls the <code>suspend</code> method on all the
676      * threads in this thread group and in all of its subgroups.
677      *
678      * @exception  SecurityException  if the current thread is not allowed
679      *               to access this thread group or any of the threads in
680      *               the thread group.
681      * @see        java.lang.Thread#suspend()
682      * @see        java.lang.SecurityException
683      * @see        java.lang.ThreadGroup#checkAccess()
684      * @since      JDK1.0
685      * @deprecated    This method is inherently deadlock-prone.  See
686      *     {@link Thread#suspend} for details.
687      */
688     @Deprecated
689     @SuppressWarnings("deprecation")
suspend()690     public final void suspend() {
691         if (stopOrSuspend(true))
692             Thread.currentThread().suspend();
693     }
694 
695     /**
696      * Helper method: recursively stops or suspends (as directed by the
697      * boolean argument) all of the threads in this thread group and its
698      * subgroups, except the current thread.  This method returns true
699      * if (and only if) the current thread is found to be in this thread
700      * group or one of its subgroups.
701      */
702     @SuppressWarnings("deprecation")
stopOrSuspend(boolean suspend)703     private boolean stopOrSuspend(boolean suspend) {
704         boolean suicide = false;
705         Thread us = Thread.currentThread();
706         int ngroupsSnapshot;
707         ThreadGroup[] groupsSnapshot = null;
708         synchronized (this) {
709             checkAccess();
710             for (int i = 0 ; i < nthreads ; i++) {
711                 if (threads[i]==us)
712                     suicide = true;
713                 else if (suspend)
714                     threads[i].suspend();
715                 else
716                     threads[i].stop();
717             }
718 
719             ngroupsSnapshot = ngroups;
720             if (groups != null) {
721                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
722             }
723         }
724         for (int i = 0 ; i < ngroupsSnapshot ; i++)
725             suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
726 
727         return suicide;
728     }
729 
730     /**
731      * Resumes all threads in this thread group.
732      * <p>
733      * First, the <code>checkAccess</code> method of this thread group is
734      * called with no arguments; this may result in a security exception.
735      * <p>
736      * This method then calls the <code>resume</code> method on all the
737      * threads in this thread group and in all of its sub groups.
738      *
739      * @exception  SecurityException  if the current thread is not allowed to
740      *               access this thread group or any of the threads in the
741      *               thread group.
742      * @see        java.lang.SecurityException
743      * @see        java.lang.Thread#resume()
744      * @see        java.lang.ThreadGroup#checkAccess()
745      * @since      JDK1.0
746      * @deprecated    This method is used solely in conjunction with
747      *      <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
748      *       both of which have been deprecated, as they are inherently
749      *       deadlock-prone.  See {@link Thread#suspend} for details.
750      */
751     @Deprecated
752     @SuppressWarnings("deprecation")
resume()753     public final void resume() {
754         int ngroupsSnapshot;
755         ThreadGroup[] groupsSnapshot;
756         synchronized (this) {
757             checkAccess();
758             for (int i = 0 ; i < nthreads ; i++) {
759                 threads[i].resume();
760             }
761             ngroupsSnapshot = ngroups;
762             if (groups != null) {
763                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
764             } else {
765                 groupsSnapshot = null;
766             }
767         }
768         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
769             groupsSnapshot[i].resume();
770         }
771     }
772 
773     /**
774      * Destroys this thread group and all of its subgroups. This thread
775      * group must be empty, indicating that all threads that had been in
776      * this thread group have since stopped.
777      * <p>
778      * First, the <code>checkAccess</code> method of this thread group is
779      * called with no arguments; this may result in a security exception.
780      *
781      * @exception  IllegalThreadStateException  if the thread group is not
782      *               empty or if the thread group has already been destroyed.
783      * @exception  SecurityException  if the current thread cannot modify this
784      *               thread group.
785      * @see        java.lang.ThreadGroup#checkAccess()
786      * @since      JDK1.0
787      */
destroy()788     public final void destroy() {
789         int ngroupsSnapshot;
790         ThreadGroup[] groupsSnapshot;
791         synchronized (this) {
792             checkAccess();
793             if (destroyed || (nthreads > 0)) {
794                 throw new IllegalThreadStateException();
795             }
796             ngroupsSnapshot = ngroups;
797             if (groups != null) {
798                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
799             } else {
800                 groupsSnapshot = null;
801             }
802             if (parent != null) {
803                 destroyed = true;
804                 ngroups = 0;
805                 groups = null;
806                 nthreads = 0;
807                 threads = null;
808             }
809         }
810         for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
811             groupsSnapshot[i].destroy();
812         }
813         if (parent != null) {
814             parent.remove(this);
815         }
816     }
817 
818     /**
819      * Adds the specified Thread group to this group.
820      * @param g the specified Thread group to be added
821      * @exception IllegalThreadStateException If the Thread group has been destroyed.
822      */
add(ThreadGroup g)823     private final void add(ThreadGroup g){
824         synchronized (this) {
825             if (destroyed) {
826                 throw new IllegalThreadStateException();
827             }
828             if (groups == null) {
829                 groups = new ThreadGroup[4];
830             } else if (ngroups == groups.length) {
831                 groups = Arrays.copyOf(groups, ngroups * 2);
832             }
833             groups[ngroups] = g;
834 
835             // This is done last so it doesn't matter in case the
836             // thread is killed
837             ngroups++;
838         }
839     }
840 
841     /**
842      * Removes the specified Thread group from this group.
843      * @param g the Thread group to be removed
844      * @return if this Thread has already been destroyed.
845      */
remove(ThreadGroup g)846     private void remove(ThreadGroup g) {
847         synchronized (this) {
848             if (destroyed) {
849                 return;
850             }
851             for (int i = 0 ; i < ngroups ; i++) {
852                 if (groups[i] == g) {
853                     ngroups -= 1;
854                     System.arraycopy(groups, i + 1, groups, i, ngroups - i);
855                     // Zap dangling reference to the dead group so that
856                     // the garbage collector will collect it.
857                     groups[ngroups] = null;
858                     break;
859                 }
860             }
861             if (nthreads == 0) {
862                 notifyAll();
863             }
864             if (daemon && (nthreads == 0) &&
865                 (nUnstartedThreads == 0) && (ngroups == 0))
866             {
867                 destroy();
868             }
869         }
870     }
871 
872 
873     /**
874      * Increments the count of unstarted threads in the thread group.
875      * Unstarted threads are not added to the thread group so that they
876      * can be collected if they are never started, but they must be
877      * counted so that daemon thread groups with unstarted threads in
878      * them are not destroyed.
879      */
addUnstarted()880     void addUnstarted() {
881         synchronized(this) {
882             if (destroyed) {
883                 throw new IllegalThreadStateException();
884             }
885             nUnstartedThreads++;
886         }
887     }
888 
889     /**
890      * Adds the specified thread to this thread group.
891      *
892      * <p> Note: This method is called from both library code
893      * and the Virtual Machine. It is called from VM to add
894      * certain system threads to the system thread group.
895      *
896      * @param  t
897      *         the Thread to be added
898      *
899      * @throws  IllegalThreadStateException
900      *          if the Thread group has been destroyed
901      */
add(Thread t)902     void add(Thread t) {
903         synchronized (this) {
904             if (destroyed) {
905                 throw new IllegalThreadStateException();
906             }
907             if (threads == null) {
908                 threads = new Thread[4];
909             } else if (nthreads == threads.length) {
910                 threads = Arrays.copyOf(threads, nthreads * 2);
911             }
912             threads[nthreads] = t;
913 
914             // This is done last so it doesn't matter in case the
915             // thread is killed
916             nthreads++;
917 
918             // The thread is now a fully fledged member of the group, even
919             // though it may, or may not, have been started yet. It will prevent
920             // the group from being destroyed so the unstarted Threads count is
921             // decremented.
922             nUnstartedThreads--;
923         }
924     }
925 
926     /**
927      * Notifies the group that the thread {@code t} has failed
928      * an attempt to start.
929      *
930      * <p> The state of this thread group is rolled back as if the
931      * attempt to start the thread has never occurred. The thread is again
932      * considered an unstarted member of the thread group, and a subsequent
933      * attempt to start the thread is permitted.
934      *
935      * @param  t
936      *         the Thread whose start method was invoked
937      */
threadStartFailed(Thread t)938     void threadStartFailed(Thread t) {
939         synchronized(this) {
940             remove(t);
941             nUnstartedThreads++;
942         }
943     }
944 
945     /**
946      * Notifies the group that the thread {@code t} has terminated.
947      *
948      * <p> Destroy the group if all of the following conditions are
949      * true: this is a daemon thread group; there are no more alive
950      * or unstarted threads in the group; there are no subgroups in
951      * this thread group.
952      *
953      * @param  t
954      *         the Thread that has terminated
955      */
threadTerminated(Thread t)956     void threadTerminated(Thread t) {
957         synchronized (this) {
958             remove(t);
959 
960             if (nthreads == 0) {
961                 notifyAll();
962             }
963             if (daemon && (nthreads == 0) &&
964                 (nUnstartedThreads == 0) && (ngroups == 0))
965             {
966                 destroy();
967             }
968         }
969     }
970 
971     /**
972      * Removes the specified Thread from this group. Invoking this method
973      * on a thread group that has been destroyed has no effect.
974      *
975      * @param  t
976      *         the Thread to be removed
977      */
remove(Thread t)978     private void remove(Thread t) {
979         synchronized (this) {
980             if (destroyed) {
981                 return;
982             }
983             for (int i = 0 ; i < nthreads ; i++) {
984                 if (threads[i] == t) {
985                     System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
986                     // Zap dangling reference to the dead thread so that
987                     // the garbage collector will collect it.
988                     threads[nthreads] = null;
989                     break;
990                 }
991             }
992         }
993     }
994 
995     /**
996      * Prints information about this thread group to the standard
997      * output. This method is useful only for debugging.
998      *
999      * @since   JDK1.0
1000      */
list()1001     public void list() {
1002         list(System.out, 0);
1003     }
list(PrintStream out, int indent)1004     void list(PrintStream out, int indent) {
1005         int ngroupsSnapshot;
1006         ThreadGroup[] groupsSnapshot;
1007         synchronized (this) {
1008             for (int j = 0 ; j < indent ; j++) {
1009                 out.print(" ");
1010             }
1011             out.println(this);
1012             indent += 4;
1013             for (int i = 0 ; i < nthreads ; i++) {
1014                 for (int j = 0 ; j < indent ; j++) {
1015                     out.print(" ");
1016                 }
1017                 out.println(threads[i]);
1018             }
1019             ngroupsSnapshot = ngroups;
1020             if (groups != null) {
1021                 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1022             } else {
1023                 groupsSnapshot = null;
1024             }
1025         }
1026         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1027             groupsSnapshot[i].list(out, indent);
1028         }
1029     }
1030 
1031     /**
1032      * Called by the Java Virtual Machine when a thread in this
1033      * thread group stops because of an uncaught exception, and the thread
1034      * does not have a specific {@link Thread.UncaughtExceptionHandler}
1035      * installed.
1036      * <p>
1037      * The <code>uncaughtException</code> method of
1038      * <code>ThreadGroup</code> does the following:
1039      * <ul>
1040      * <li>If this thread group has a parent thread group, the
1041      *     <code>uncaughtException</code> method of that parent is called
1042      *     with the same two arguments.
1043      * <li>Otherwise, this method checks to see if there is a
1044      *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
1045      *     uncaught exception handler} installed, and if so, its
1046      *     <code>uncaughtException</code> method is called with the same
1047      *     two arguments.
1048      * <li>Otherwise, this method determines if the <code>Throwable</code>
1049      *     argument is an instance of {@link ThreadDeath}. If so, nothing
1050      *     special is done. Otherwise, a message containing the
1051      *     thread's name, as returned from the thread's {@link
1052      *     Thread#getName getName} method, and a stack backtrace,
1053      *     using the <code>Throwable</code>'s {@link
1054      *     Throwable#printStackTrace printStackTrace} method, is
1055      *     printed to the {@linkplain System#err standard error stream}.
1056      * </ul>
1057      * <p>
1058      * Applications can override this method in subclasses of
1059      * <code>ThreadGroup</code> to provide alternative handling of
1060      * uncaught exceptions.
1061      *
1062      * @param   t   the thread that is about to exit.
1063      * @param   e   the uncaught exception.
1064      * @since   JDK1.0
1065      */
uncaughtException(Thread t, Throwable e)1066     public void uncaughtException(Thread t, Throwable e) {
1067         if (parent != null) {
1068             parent.uncaughtException(t, e);
1069         } else {
1070             Thread.UncaughtExceptionHandler ueh =
1071                 Thread.getDefaultUncaughtExceptionHandler();
1072             if (ueh != null) {
1073                 ueh.uncaughtException(t, e);
1074             } else if (!(e instanceof ThreadDeath)) {
1075                 System.err.print("Exception in thread \""
1076                                  + t.getName() + "\" ");
1077                 e.printStackTrace(System.err);
1078             }
1079         }
1080     }
1081 
1082     /**
1083      * Used by VM to control lowmem implicit suspension.
1084      *
1085      * @param b boolean to allow or disallow suspension
1086      * @return true on success
1087      * @since   JDK1.1
1088      * @deprecated The definition of this call depends on {@link #suspend},
1089      *             which is deprecated.  Further, the behavior of this call
1090      *             was never specified.
1091      */
1092     @Deprecated
allowThreadSuspension(boolean b)1093     public boolean allowThreadSuspension(boolean b) {
1094         this.vmAllowSuspension = b;
1095         if (!b) {
1096             VM.unsuspendSomeThreads();
1097         }
1098         return true;
1099     }
1100 
1101     /**
1102      * Returns a string representation of this Thread group.
1103      *
1104      * @return  a string representation of this thread group.
1105      * @since   JDK1.0
1106      */
toString()1107     public String toString() {
1108         return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
1109     }
1110 }
1111