0001: /*
0002: * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package java.lang;
0027:
0028: import java.io.PrintStream;
0029: import java.util.Arrays;
0030: import sun.misc.VM;
0031:
0032: /**
0033: * A thread group represents a set of threads. In addition, a thread
0034: * group can also include other thread groups. The thread groups form
0035: * a tree in which every thread group except the initial thread group
0036: * has a parent.
0037: * <p>
0038: * A thread is allowed to access information about its own thread
0039: * group, but not to access information about its thread group's
0040: * parent thread group or any other thread groups.
0041: *
0042: * @author unascribed
0043: * @version 1.73, 06/27/07
0044: * @since JDK1.0
0045: */
0046: /* The locking strategy for this code is to try to lock only one level of the
0047: * tree wherever possible, but otherwise to lock from the bottom up.
0048: * That is, from child thread groups to parents.
0049: * This has the advantage of limiting the number of locks that need to be held
0050: * and in particular avoids having to grab the lock for the root thread group,
0051: * (or a global lock) which would be a source of contention on a
0052: * multi-processor system with many thread groups.
0053: * This policy often leads to taking a snapshot of the state of a thread group
0054: * and working off of that snapshot, rather than holding the thread group locked
0055: * while we work on the children.
0056: */
0057: public class ThreadGroup implements Thread.UncaughtExceptionHandler {
0058: ThreadGroup parent;
0059: String name;
0060: int maxPriority;
0061: boolean destroyed;
0062: boolean daemon;
0063: boolean vmAllowSuspension;
0064:
0065: int nUnstartedThreads = 0;
0066: int nthreads;
0067: Thread threads[];
0068:
0069: int ngroups;
0070: ThreadGroup groups[];
0071:
0072: /**
0073: * Creates an empty Thread group that is not in any Thread group.
0074: * This method is used to create the system Thread group.
0075: */
0076: private ThreadGroup() { // called from C code
0077: this .name = "system";
0078: this .maxPriority = Thread.MAX_PRIORITY;
0079: }
0080:
0081: /**
0082: * Constructs a new thread group. The parent of this new group is
0083: * the thread group of the currently running thread.
0084: * <p>
0085: * The <code>checkAccess</code> method of the parent thread group is
0086: * called with no arguments; this may result in a security exception.
0087: *
0088: * @param name the name of the new thread group.
0089: * @exception SecurityException if the current thread cannot create a
0090: * thread in the specified thread group.
0091: * @see java.lang.ThreadGroup#checkAccess()
0092: * @since JDK1.0
0093: */
0094: public ThreadGroup(String name) {
0095: this (Thread.currentThread().getThreadGroup(), name);
0096: }
0097:
0098: /**
0099: * Creates a new thread group. The parent of this new group is the
0100: * specified thread group.
0101: * <p>
0102: * The <code>checkAccess</code> method of the parent thread group is
0103: * called with no arguments; this may result in a security exception.
0104: *
0105: * @param parent the parent thread group.
0106: * @param name the name of the new thread group.
0107: * @exception NullPointerException if the thread group argument is
0108: * <code>null</code>.
0109: * @exception SecurityException if the current thread cannot create a
0110: * thread in the specified thread group.
0111: * @see java.lang.SecurityException
0112: * @see java.lang.ThreadGroup#checkAccess()
0113: * @since JDK1.0
0114: */
0115: public ThreadGroup(ThreadGroup parent, String name) {
0116: if (parent == null) {
0117: throw new NullPointerException();
0118: }
0119: parent.checkAccess();
0120: this .name = name;
0121: this .maxPriority = parent.maxPriority;
0122: this .daemon = parent.daemon;
0123: this .vmAllowSuspension = parent.vmAllowSuspension;
0124: this .parent = parent;
0125: parent.add(this );
0126: }
0127:
0128: /**
0129: * Returns the name of this thread group.
0130: *
0131: * @return the name of this thread group.
0132: * @since JDK1.0
0133: */
0134: public final String getName() {
0135: return name;
0136: }
0137:
0138: /**
0139: * Returns the parent of this thread group.
0140: * <p>
0141: * First, if the parent is not <code>null</code>, the
0142: * <code>checkAccess</code> method of the parent thread group is
0143: * called with no arguments; this may result in a security exception.
0144: *
0145: * @return the parent of this thread group. The top-level thread group
0146: * is the only thread group whose parent is <code>null</code>.
0147: * @exception SecurityException if the current thread cannot modify
0148: * this thread group.
0149: * @see java.lang.ThreadGroup#checkAccess()
0150: * @see java.lang.SecurityException
0151: * @see java.lang.RuntimePermission
0152: * @since JDK1.0
0153: */
0154: public final ThreadGroup getParent() {
0155: if (parent != null)
0156: parent.checkAccess();
0157: return parent;
0158: }
0159:
0160: /**
0161: * Returns the maximum priority of this thread group. Threads that are
0162: * part of this group cannot have a higher priority than the maximum
0163: * priority.
0164: *
0165: * @return the maximum priority that a thread in this thread group
0166: * can have.
0167: * @see #setMaxPriority
0168: * @since JDK1.0
0169: */
0170: public final int getMaxPriority() {
0171: return maxPriority;
0172: }
0173:
0174: /**
0175: * Tests if this thread group is a daemon thread group. A
0176: * daemon thread group is automatically destroyed when its last
0177: * thread is stopped or its last thread group is destroyed.
0178: *
0179: * @return <code>true</code> if this thread group is a daemon thread group;
0180: * <code>false</code> otherwise.
0181: * @since JDK1.0
0182: */
0183: public final boolean isDaemon() {
0184: return daemon;
0185: }
0186:
0187: /**
0188: * Tests if this thread group has been destroyed.
0189: *
0190: * @return true if this object is destroyed
0191: * @since JDK1.1
0192: */
0193: public synchronized boolean isDestroyed() {
0194: return destroyed;
0195: }
0196:
0197: /**
0198: * Changes the daemon status of this thread group.
0199: * <p>
0200: * First, the <code>checkAccess</code> method of this thread group is
0201: * called with no arguments; this may result in a security exception.
0202: * <p>
0203: * A daemon thread group is automatically destroyed when its last
0204: * thread is stopped or its last thread group is destroyed.
0205: *
0206: * @param daemon if <code>true</code>, marks this thread group as
0207: * a daemon thread group; otherwise, marks this
0208: * thread group as normal.
0209: * @exception SecurityException if the current thread cannot modify
0210: * this thread group.
0211: * @see java.lang.SecurityException
0212: * @see java.lang.ThreadGroup#checkAccess()
0213: * @since JDK1.0
0214: */
0215: public final void setDaemon(boolean daemon) {
0216: checkAccess();
0217: this .daemon = daemon;
0218: }
0219:
0220: /**
0221: * Sets the maximum priority of the group. Threads in the thread
0222: * group that already have a higher priority are not affected.
0223: * <p>
0224: * First, the <code>checkAccess</code> method of this thread group is
0225: * called with no arguments; this may result in a security exception.
0226: * <p>
0227: * If the <code>pri</code> argument is less than
0228: * {@link Thread#MIN_PRIORITY} or greater than
0229: * {@link Thread#MAX_PRIORITY}, the maximum priority of the group
0230: * remains unchanged.
0231: * <p>
0232: * Otherwise, the priority of this ThreadGroup object is set to the
0233: * smaller of the specified <code>pri</code> and the maximum permitted
0234: * priority of the parent of this thread group. (If this thread group
0235: * is the system thread group, which has no parent, then its maximum
0236: * priority is simply set to <code>pri</code>.) Then this method is
0237: * called recursively, with <code>pri</code> as its argument, for
0238: * every thread group that belongs to this thread group.
0239: *
0240: * @param pri the new priority of the thread group.
0241: * @exception SecurityException if the current thread cannot modify
0242: * this thread group.
0243: * @see #getMaxPriority
0244: * @see java.lang.SecurityException
0245: * @see java.lang.ThreadGroup#checkAccess()
0246: * @since JDK1.0
0247: */
0248: public final void setMaxPriority(int pri) {
0249: int ngroupsSnapshot;
0250: ThreadGroup[] groupsSnapshot;
0251: synchronized (this ) {
0252: checkAccess();
0253: if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
0254: return;
0255: }
0256: maxPriority = (parent != null) ? Math.min(pri,
0257: parent.maxPriority) : pri;
0258: ngroupsSnapshot = ngroups;
0259: if (groups != null) {
0260: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0261: } else {
0262: groupsSnapshot = null;
0263: }
0264: }
0265: for (int i = 0; i < ngroupsSnapshot; i++) {
0266: groupsSnapshot[i].setMaxPriority(pri);
0267: }
0268: }
0269:
0270: /**
0271: * Tests if this thread group is either the thread group
0272: * argument or one of its ancestor thread groups.
0273: *
0274: * @param g a thread group.
0275: * @return <code>true</code> if this thread group is the thread group
0276: * argument or one of its ancestor thread groups;
0277: * <code>false</code> otherwise.
0278: * @since JDK1.0
0279: */
0280: public final boolean parentOf(ThreadGroup g) {
0281: for (; g != null; g = g.parent) {
0282: if (g == this ) {
0283: return true;
0284: }
0285: }
0286: return false;
0287: }
0288:
0289: /**
0290: * Determines if the currently running thread has permission to
0291: * modify this thread group.
0292: * <p>
0293: * If there is a security manager, its <code>checkAccess</code> method
0294: * is called with this thread group as its argument. This may result
0295: * in throwing a <code>SecurityException</code>.
0296: *
0297: * @exception SecurityException if the current thread is not allowed to
0298: * access this thread group.
0299: * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
0300: * @since JDK1.0
0301: */
0302: public final void checkAccess() {
0303: SecurityManager security = System.getSecurityManager();
0304: if (security != null) {
0305: security.checkAccess(this );
0306: }
0307: }
0308:
0309: /**
0310: * Returns an estimate of the number of active threads in this
0311: * thread group. The result might not reflect concurrent activity,
0312: * and might be affected by the presence of certain system threads.
0313: * <p>
0314: * Due to the inherently imprecise nature of the result, it is
0315: * recommended that this method only be used for informational purposes.
0316: *
0317: * @return an estimate of the number of active threads in this thread
0318: * group and in any other thread group that has this thread
0319: * group as an ancestor.
0320: * @since JDK1.0
0321: */
0322: public int activeCount() {
0323: int result;
0324: // Snapshot sub-group data so we don't hold this lock
0325: // while our children are computing.
0326: int ngroupsSnapshot;
0327: ThreadGroup[] groupsSnapshot;
0328: synchronized (this ) {
0329: if (destroyed) {
0330: return 0;
0331: }
0332: result = nthreads;
0333: ngroupsSnapshot = ngroups;
0334: if (groups != null) {
0335: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0336: } else {
0337: groupsSnapshot = null;
0338: }
0339: }
0340: for (int i = 0; i < ngroupsSnapshot; i++) {
0341: result += groupsSnapshot[i].activeCount();
0342: }
0343: return result;
0344: }
0345:
0346: /**
0347: * Copies into the specified array every active thread in this
0348: * thread group and its subgroups.
0349: * <p>
0350: * First, the <code>checkAccess</code> method of this thread group is
0351: * called with no arguments; this may result in a security exception.
0352: * <p>
0353: * An application might use the <code>activeCount</code> method to
0354: * get an estimate of how big the array should be, however <i>if the
0355: * array is too short to hold all the threads, the extra threads are
0356: * silently ignored.</i> If it is critical to obtain every active
0357: * thread in this thread group and its subgroups, the caller should
0358: * verify that the returned int value is strictly less than the length
0359: * of <tt>list</tt>.
0360: * <p>
0361: * Due to the inherent race condition in this method, it is recommended
0362: * that the method only be used for informational purposes.
0363: *
0364: * @param list an array into which to place the list of threads.
0365: * @return the number of threads put into the array.
0366: * @exception SecurityException if the current thread does not
0367: * have permission to enumerate this thread group.
0368: * @see java.lang.ThreadGroup#activeCount()
0369: * @see java.lang.ThreadGroup#checkAccess()
0370: * @since JDK1.0
0371: */
0372: public int enumerate(Thread list[]) {
0373: checkAccess();
0374: return enumerate(list, 0, true);
0375: }
0376:
0377: /**
0378: * Copies into the specified array every active thread in this
0379: * thread group. If the <code>recurse</code> flag is
0380: * <code>true</code>, references to every active thread in this
0381: * thread's subgroups are also included. If the array is too short to
0382: * hold all the threads, the extra threads are silently ignored.
0383: * <p>
0384: * First, the <code>checkAccess</code> method of this thread group is
0385: * called with no arguments; this may result in a security exception.
0386: * <p>
0387: * An application might use the <code>activeCount</code> method to
0388: * get an estimate of how big the array should be, however <i>if the
0389: * array is too short to hold all the threads, the extra threads are
0390: * silently ignored.</i> If it is critical to obtain every active thread
0391: * in this thread group, the caller should verify that the returned int
0392: * value is strictly less than the length of <tt>list</tt>.
0393: * <p>
0394: * Due to the inherent race condition in this method, it is recommended
0395: * that the method only be used for informational purposes.
0396: *
0397: * @param list an array into which to place the list of threads.
0398: * @param recurse a flag indicating whether also to include threads
0399: * in thread groups that are subgroups of this
0400: * thread group.
0401: * @return the number of threads placed into the array.
0402: * @exception SecurityException if the current thread does not
0403: * have permission to enumerate this thread group.
0404: * @see java.lang.ThreadGroup#activeCount()
0405: * @see java.lang.ThreadGroup#checkAccess()
0406: * @since JDK1.0
0407: */
0408: public int enumerate(Thread list[], boolean recurse) {
0409: checkAccess();
0410: return enumerate(list, 0, recurse);
0411: }
0412:
0413: private int enumerate(Thread list[], int n, boolean recurse) {
0414: int ngroupsSnapshot = 0;
0415: ThreadGroup[] groupsSnapshot = null;
0416: synchronized (this ) {
0417: if (destroyed) {
0418: return 0;
0419: }
0420: int nt = nthreads;
0421: if (nt > list.length - n) {
0422: nt = list.length - n;
0423: }
0424: for (int i = 0; i < nt; i++) {
0425: if (threads[i].isAlive()) {
0426: list[n++] = threads[i];
0427: }
0428: }
0429: if (recurse) {
0430: ngroupsSnapshot = ngroups;
0431: if (groups != null) {
0432: groupsSnapshot = Arrays.copyOf(groups,
0433: ngroupsSnapshot);
0434: } else {
0435: groupsSnapshot = null;
0436: }
0437: }
0438: }
0439: if (recurse) {
0440: for (int i = 0; i < ngroupsSnapshot; i++) {
0441: n = groupsSnapshot[i].enumerate(list, n, true);
0442: }
0443: }
0444: return n;
0445: }
0446:
0447: /**
0448: * Returns an estimate of the number of active groups in this
0449: * thread group. The result might not reflect concurrent activity.
0450: * <p>
0451: * Due to the inherently imprecise nature of the result, it is
0452: * recommended that this method only be used for informational purposes.
0453: *
0454: * @return the number of active thread groups with this thread group as
0455: * an ancestor.
0456: * @since JDK1.0
0457: */
0458: public int activeGroupCount() {
0459: int ngroupsSnapshot;
0460: ThreadGroup[] groupsSnapshot;
0461: synchronized (this ) {
0462: if (destroyed) {
0463: return 0;
0464: }
0465: ngroupsSnapshot = ngroups;
0466: if (groups != null) {
0467: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0468: } else {
0469: groupsSnapshot = null;
0470: }
0471: }
0472: int n = ngroupsSnapshot;
0473: for (int i = 0; i < ngroupsSnapshot; i++) {
0474: n += groupsSnapshot[i].activeGroupCount();
0475: }
0476: return n;
0477: }
0478:
0479: /**
0480: * Copies into the specified array references to every active
0481: * subgroup in this thread group.
0482: * <p>
0483: * First, the <code>checkAccess</code> method of this thread group is
0484: * called with no arguments; this may result in a security exception.
0485: * <p>
0486: * An application might use the <code>activeGroupCount</code> method to
0487: * get an estimate of how big the array should be, however <i>if the
0488: * array is too short to hold all the thread groups, the extra thread
0489: * groups are silently ignored.</i> If it is critical to obtain every
0490: * active subgroup in this thread group, the caller should verify that
0491: * the returned int value is strictly less than the length of
0492: * <tt>list</tt>.
0493: * <p>
0494: * Due to the inherent race condition in this method, it is recommended
0495: * that the method only be used for informational purposes.
0496: *
0497: * @param list an array into which to place the list of thread groups.
0498: * @return the number of thread groups put into the array.
0499: * @exception SecurityException if the current thread does not
0500: * have permission to enumerate this thread group.
0501: * @see java.lang.ThreadGroup#activeGroupCount()
0502: * @see java.lang.ThreadGroup#checkAccess()
0503: * @since JDK1.0
0504: */
0505: public int enumerate(ThreadGroup list[]) {
0506: checkAccess();
0507: return enumerate(list, 0, true);
0508: }
0509:
0510: /**
0511: * Copies into the specified array references to every active
0512: * subgroup in this thread group. If the <code>recurse</code> flag is
0513: * <code>true</code>, references to all active subgroups of the
0514: * subgroups and so forth are also included.
0515: * <p>
0516: * First, the <code>checkAccess</code> method of this thread group is
0517: * called with no arguments; this may result in a security exception.
0518: * <p>
0519: * An application might use the <code>activeGroupCount</code> method to
0520: * get an estimate of how big the array should be, however <i>if the
0521: * array is too short to hold all the thread groups, the extra thread
0522: * groups are silently ignored.</i> If it is critical to obtain every
0523: * active subgroup in this thread group, the caller should verify that
0524: * the returned int value is strictly less than the length of
0525: * <tt>list</tt>.
0526: * <p>
0527: * Due to the inherent race condition in this method, it is recommended
0528: * that the method only be used for informational purposes.
0529: *
0530: * @param list an array into which to place the list of threads.
0531: * @param recurse a flag indicating whether to recursively enumerate
0532: * all included thread groups.
0533: * @return the number of thread groups put into the array.
0534: * @exception SecurityException if the current thread does not
0535: * have permission to enumerate this thread group.
0536: * @see java.lang.ThreadGroup#activeGroupCount()
0537: * @see java.lang.ThreadGroup#checkAccess()
0538: * @since JDK1.0
0539: */
0540: public int enumerate(ThreadGroup list[], boolean recurse) {
0541: checkAccess();
0542: return enumerate(list, 0, recurse);
0543: }
0544:
0545: private int enumerate(ThreadGroup list[], int n, boolean recurse) {
0546: int ngroupsSnapshot = 0;
0547: ThreadGroup[] groupsSnapshot = null;
0548: synchronized (this ) {
0549: if (destroyed) {
0550: return 0;
0551: }
0552: int ng = ngroups;
0553: if (ng > list.length - n) {
0554: ng = list.length - n;
0555: }
0556: if (ng > 0) {
0557: System.arraycopy(groups, 0, list, n, ng);
0558: n += ng;
0559: }
0560: if (recurse) {
0561: ngroupsSnapshot = ngroups;
0562: if (groups != null) {
0563: groupsSnapshot = Arrays.copyOf(groups,
0564: ngroupsSnapshot);
0565: } else {
0566: groupsSnapshot = null;
0567: }
0568: }
0569: }
0570: if (recurse) {
0571: for (int i = 0; i < ngroupsSnapshot; i++) {
0572: n = groupsSnapshot[i].enumerate(list, n, true);
0573: }
0574: }
0575: return n;
0576: }
0577:
0578: /**
0579: * Stops all threads in this thread group.
0580: * <p>
0581: * First, the <code>checkAccess</code> method of this thread group is
0582: * called with no arguments; this may result in a security exception.
0583: * <p>
0584: * This method then calls the <code>stop</code> method on all the
0585: * threads in this thread group and in all of its subgroups.
0586: *
0587: * @exception SecurityException if the current thread is not allowed
0588: * to access this thread group or any of the threads in
0589: * the thread group.
0590: * @see java.lang.SecurityException
0591: * @see java.lang.Thread#stop()
0592: * @see java.lang.ThreadGroup#checkAccess()
0593: * @since JDK1.0
0594: * @deprecated This method is inherently unsafe. See
0595: * {@link Thread#stop} for details.
0596: */
0597: @Deprecated
0598: public final void stop() {
0599: if (stopOrSuspend(false))
0600: Thread.currentThread().stop();
0601: }
0602:
0603: /**
0604: * Interrupts all threads in this thread group.
0605: * <p>
0606: * First, the <code>checkAccess</code> method of this thread group is
0607: * called with no arguments; this may result in a security exception.
0608: * <p>
0609: * This method then calls the <code>interrupt</code> method on all the
0610: * threads in this thread group and in all of its subgroups.
0611: *
0612: * @exception SecurityException if the current thread is not allowed
0613: * to access this thread group or any of the threads in
0614: * the thread group.
0615: * @see java.lang.Thread#interrupt()
0616: * @see java.lang.SecurityException
0617: * @see java.lang.ThreadGroup#checkAccess()
0618: * @since 1.2
0619: */
0620: public final void interrupt() {
0621: int ngroupsSnapshot;
0622: ThreadGroup[] groupsSnapshot;
0623: synchronized (this ) {
0624: checkAccess();
0625: for (int i = 0; i < nthreads; i++) {
0626: threads[i].interrupt();
0627: }
0628: ngroupsSnapshot = ngroups;
0629: if (groups != null) {
0630: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0631: } else {
0632: groupsSnapshot = null;
0633: }
0634: }
0635: for (int i = 0; i < ngroupsSnapshot; i++) {
0636: groupsSnapshot[i].interrupt();
0637: }
0638: }
0639:
0640: /**
0641: * Suspends all threads in this thread group.
0642: * <p>
0643: * First, the <code>checkAccess</code> method of this thread group is
0644: * called with no arguments; this may result in a security exception.
0645: * <p>
0646: * This method then calls the <code>suspend</code> method on all the
0647: * threads in this thread group and in all of its subgroups.
0648: *
0649: * @exception SecurityException if the current thread is not allowed
0650: * to access this thread group or any of the threads in
0651: * the thread group.
0652: * @see java.lang.Thread#suspend()
0653: * @see java.lang.SecurityException
0654: * @see java.lang.ThreadGroup#checkAccess()
0655: * @since JDK1.0
0656: * @deprecated This method is inherently deadlock-prone. See
0657: * {@link Thread#suspend} for details.
0658: */
0659: @Deprecated
0660: public final void suspend() {
0661: if (stopOrSuspend(true))
0662: Thread.currentThread().suspend();
0663: }
0664:
0665: /**
0666: * Helper method: recursively stops or suspends (as directed by the
0667: * boolean argument) all of the threads in this thread group and its
0668: * subgroups, except the current thread. This method returns true
0669: * if (and only if) the current thread is found to be in this thread
0670: * group or one of its subgroups.
0671: */
0672: private boolean stopOrSuspend(boolean suspend) {
0673: boolean suicide = false;
0674: Thread us = Thread.currentThread();
0675: int ngroupsSnapshot;
0676: ThreadGroup[] groupsSnapshot = null;
0677: synchronized (this ) {
0678: checkAccess();
0679: for (int i = 0; i < nthreads; i++) {
0680: if (threads[i] == us)
0681: suicide = true;
0682: else if (suspend)
0683: threads[i].suspend();
0684: else
0685: threads[i].stop();
0686: }
0687:
0688: ngroupsSnapshot = ngroups;
0689: if (groups != null) {
0690: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0691: }
0692: }
0693: for (int i = 0; i < ngroupsSnapshot; i++)
0694: suicide = groupsSnapshot[i].stopOrSuspend(suspend)
0695: || suicide;
0696:
0697: return suicide;
0698: }
0699:
0700: /**
0701: * Resumes all threads in this thread group.
0702: * <p>
0703: * First, the <code>checkAccess</code> method of this thread group is
0704: * called with no arguments; this may result in a security exception.
0705: * <p>
0706: * This method then calls the <code>resume</code> method on all the
0707: * threads in this thread group and in all of its sub groups.
0708: *
0709: * @exception SecurityException if the current thread is not allowed to
0710: * access this thread group or any of the threads in the
0711: * thread group.
0712: * @see java.lang.SecurityException
0713: * @see java.lang.Thread#resume()
0714: * @see java.lang.ThreadGroup#checkAccess()
0715: * @since JDK1.0
0716: * @deprecated This method is used solely in conjunction with
0717: * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
0718: * both of which have been deprecated, as they are inherently
0719: * deadlock-prone. See {@link Thread#suspend} for details.
0720: */
0721: @Deprecated
0722: public final void resume() {
0723: int ngroupsSnapshot;
0724: ThreadGroup[] groupsSnapshot;
0725: synchronized (this ) {
0726: checkAccess();
0727: for (int i = 0; i < nthreads; i++) {
0728: threads[i].resume();
0729: }
0730: ngroupsSnapshot = ngroups;
0731: if (groups != null) {
0732: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0733: } else {
0734: groupsSnapshot = null;
0735: }
0736: }
0737: for (int i = 0; i < ngroupsSnapshot; i++) {
0738: groupsSnapshot[i].resume();
0739: }
0740: }
0741:
0742: /**
0743: * Destroys this thread group and all of its subgroups. This thread
0744: * group must be empty, indicating that all threads that had been in
0745: * this thread group have since stopped.
0746: * <p>
0747: * First, the <code>checkAccess</code> method of this thread group is
0748: * called with no arguments; this may result in a security exception.
0749: *
0750: * @exception IllegalThreadStateException if the thread group is not
0751: * empty or if the thread group has already been destroyed.
0752: * @exception SecurityException if the current thread cannot modify this
0753: * thread group.
0754: * @see java.lang.ThreadGroup#checkAccess()
0755: * @since JDK1.0
0756: */
0757: public final void destroy() {
0758: int ngroupsSnapshot;
0759: ThreadGroup[] groupsSnapshot;
0760: synchronized (this ) {
0761: checkAccess();
0762: if (destroyed || (nthreads > 0)) {
0763: throw new IllegalThreadStateException();
0764: }
0765: ngroupsSnapshot = ngroups;
0766: if (groups != null) {
0767: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0768: } else {
0769: groupsSnapshot = null;
0770: }
0771: if (parent != null) {
0772: destroyed = true;
0773: ngroups = 0;
0774: groups = null;
0775: nthreads = 0;
0776: threads = null;
0777: }
0778: }
0779: for (int i = 0; i < ngroupsSnapshot; i += 1) {
0780: groupsSnapshot[i].destroy();
0781: }
0782: if (parent != null) {
0783: parent.remove(this );
0784: }
0785: }
0786:
0787: /**
0788: * Adds the specified Thread group to this group.
0789: * @param g the specified Thread group to be added
0790: * @exception IllegalThreadStateException If the Thread group has been destroyed.
0791: */
0792: private final void add(ThreadGroup g) {
0793: synchronized (this ) {
0794: if (destroyed) {
0795: throw new IllegalThreadStateException();
0796: }
0797: if (groups == null) {
0798: groups = new ThreadGroup[4];
0799: } else if (ngroups == groups.length) {
0800: groups = Arrays.copyOf(groups, ngroups * 2);
0801: }
0802: groups[ngroups] = g;
0803:
0804: // This is done last so it doesn't matter in case the
0805: // thread is killed
0806: ngroups++;
0807: }
0808: }
0809:
0810: /**
0811: * Removes the specified Thread group from this group.
0812: * @param g the Thread group to be removed
0813: * @return if this Thread has already been destroyed.
0814: */
0815: private void remove(ThreadGroup g) {
0816: synchronized (this ) {
0817: if (destroyed) {
0818: return;
0819: }
0820: for (int i = 0; i < ngroups; i++) {
0821: if (groups[i] == g) {
0822: ngroups -= 1;
0823: System.arraycopy(groups, i + 1, groups, i, ngroups
0824: - i);
0825: // Zap dangling reference to the dead group so that
0826: // the garbage collector will collect it.
0827: groups[ngroups] = null;
0828: break;
0829: }
0830: }
0831: if (nthreads == 0) {
0832: notifyAll();
0833: }
0834: if (daemon && (nthreads == 0) && (nUnstartedThreads == 0)
0835: && (ngroups == 0)) {
0836: destroy();
0837: }
0838: }
0839: }
0840:
0841: /**
0842: * Increments the count of unstarted threads in the thread group.
0843: * Unstarted threads are not added to the thread group so that they
0844: * can be collected if they are never started, but they must be
0845: * counted so that daemon thread groups with unstarted threads in
0846: * them are not destroyed.
0847: */
0848: void addUnstarted() {
0849: synchronized (this ) {
0850: if (destroyed) {
0851: throw new IllegalThreadStateException();
0852: }
0853: nUnstartedThreads++;
0854: }
0855: }
0856:
0857: /**
0858: * Adds the specified Thread to this group.
0859: * @param t the Thread to be added
0860: * @exception IllegalThreadStateException If the Thread group has been destroyed.
0861: */
0862: void add(Thread t) {
0863: synchronized (this ) {
0864: if (destroyed) {
0865: throw new IllegalThreadStateException();
0866: }
0867: if (threads == null) {
0868: threads = new Thread[4];
0869: } else if (nthreads == threads.length) {
0870: threads = Arrays.copyOf(threads, nthreads * 2);
0871: }
0872: threads[nthreads] = t;
0873:
0874: // This is done last so it doesn't matter in case the
0875: // thread is killed
0876: nthreads++;
0877: nUnstartedThreads--;
0878: }
0879: }
0880:
0881: /**
0882: * Removes the specified Thread from this group.
0883: * @param t the Thread to be removed
0884: * @return if the Thread has already been destroyed.
0885: */
0886: void remove(Thread t) {
0887: synchronized (this ) {
0888: if (destroyed) {
0889: return;
0890: }
0891: for (int i = 0; i < nthreads; i++) {
0892: if (threads[i] == t) {
0893: System.arraycopy(threads, i + 1, threads, i,
0894: --nthreads - i);
0895: // Zap dangling reference to the dead thread so that
0896: // the garbage collector will collect it.
0897: threads[nthreads] = null;
0898: break;
0899: }
0900: }
0901: if (nthreads == 0) {
0902: notifyAll();
0903: }
0904: if (daemon && (nthreads == 0) && (nUnstartedThreads == 0)
0905: && (ngroups == 0)) {
0906: destroy();
0907: }
0908: }
0909: }
0910:
0911: /**
0912: * Prints information about this thread group to the standard
0913: * output. This method is useful only for debugging.
0914: *
0915: * @since JDK1.0
0916: */
0917: public void list() {
0918: list(System.out, 0);
0919: }
0920:
0921: void list(PrintStream out, int indent) {
0922: int ngroupsSnapshot;
0923: ThreadGroup[] groupsSnapshot;
0924: synchronized (this ) {
0925: for (int j = 0; j < indent; j++) {
0926: out.print(" ");
0927: }
0928: out.println(this );
0929: indent += 4;
0930: for (int i = 0; i < nthreads; i++) {
0931: for (int j = 0; j < indent; j++) {
0932: out.print(" ");
0933: }
0934: out.println(threads[i]);
0935: }
0936: ngroupsSnapshot = ngroups;
0937: if (groups != null) {
0938: groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
0939: } else {
0940: groupsSnapshot = null;
0941: }
0942: }
0943: for (int i = 0; i < ngroupsSnapshot; i++) {
0944: groupsSnapshot[i].list(out, indent);
0945: }
0946: }
0947:
0948: /**
0949: * Called by the Java Virtual Machine when a thread in this
0950: * thread group stops because of an uncaught exception, and the thread
0951: * does not have a specific {@link Thread.UncaughtExceptionHandler}
0952: * installed.
0953: * <p>
0954: * The <code>uncaughtException</code> method of
0955: * <code>ThreadGroup</code> does the following:
0956: * <ul>
0957: * <li>If this thread group has a parent thread group, the
0958: * <code>uncaughtException</code> method of that parent is called
0959: * with the same two arguments.
0960: * <li>Otherwise, this method checks to see if there is a
0961: * {@linkplain Thread#getDefaultUncaughtExceptionHandler default
0962: * uncaught exception handler} installed, and if so, its
0963: * <code>uncaughtException</code> method is called with the same
0964: * two arguments.
0965: * <li>Otherwise, this method determines if the <code>Throwable</code>
0966: * argument is an instance of {@link ThreadDeath}. If so, nothing
0967: * special is done. Otherwise, a message containing the
0968: * thread's name, as returned from the thread's {@link
0969: * Thread#getName getName} method, and a stack backtrace,
0970: * using the <code>Throwable</code>'s {@link
0971: * Throwable#printStackTrace printStackTrace} method, is
0972: * printed to the {@linkplain System#err standard error stream}.
0973: * </ul>
0974: * <p>
0975: * Applications can override this method in subclasses of
0976: * <code>ThreadGroup</code> to provide alternative handling of
0977: * uncaught exceptions.
0978: *
0979: * @param t the thread that is about to exit.
0980: * @param e the uncaught exception.
0981: * @since JDK1.0
0982: */
0983: public void uncaughtException(Thread t, Throwable e) {
0984: if (parent != null) {
0985: parent.uncaughtException(t, e);
0986: } else {
0987: Thread.UncaughtExceptionHandler ueh = Thread
0988: .getDefaultUncaughtExceptionHandler();
0989: if (ueh != null) {
0990: ueh.uncaughtException(t, e);
0991: } else if (!(e instanceof ThreadDeath)) {
0992: System.err.print("Exception in thread \"" + t.getName()
0993: + "\" ");
0994: e.printStackTrace(System.err);
0995: }
0996: }
0997: }
0998:
0999: /**
1000: * Used by VM to control lowmem implicit suspension.
1001: *
1002: * @param b boolean to allow or disallow suspension
1003: * @return true on success
1004: * @since JDK1.1
1005: * @deprecated The definition of this call depends on {@link #suspend},
1006: * which is deprecated. Further, the behavior of this call
1007: * was never specified.
1008: */
1009: @Deprecated
1010: public boolean allowThreadSuspension(boolean b) {
1011: this .vmAllowSuspension = b;
1012: if (!b) {
1013: VM.unsuspendSomeThreads();
1014: }
1015: return true;
1016: }
1017:
1018: /**
1019: * Returns a string representation of this Thread group.
1020: *
1021: * @return a string representation of this thread group.
1022: * @since JDK1.0
1023: */
1024: public String toString() {
1025: return getClass().getName() + "[name=" + getName() + ",maxpri="
1026: + maxPriority + "]";
1027: }
1028: }
|