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