History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/lang/ThreadGroup.java (1 of 18352 files). Show all

Unified · Split

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