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