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+
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+ 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+}