0001: /*
0002: * @(#)ThreadGroup.java 1.63 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package java.lang;
0029:
0030: import java.io.PrintStream;
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.55 07/27/01
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 {
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: ThreadGroup() { // called from Thread.initMainThread()
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) {
0254: maxPriority = Thread.MIN_PRIORITY;
0255: } else if (pri < maxPriority) {
0256: maxPriority = pri;
0257: }
0258: ngroupsSnapshot = ngroups;
0259: if (groups != null) {
0260: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0261: System.arraycopy(groups, 0, groupsSnapshot, 0,
0262: ngroupsSnapshot);
0263: } else {
0264: groupsSnapshot = null;
0265: }
0266: }
0267: for (int i = 0; i < ngroupsSnapshot; i++) {
0268: groupsSnapshot[i].setMaxPriority(pri);
0269: }
0270: }
0271:
0272: /**
0273: * Tests if this thread group is either the thread group
0274: * argument or one of its ancestor thread groups.
0275: *
0276: * @param g a thread group.
0277: * @return <code>true</code> if this thread group is the thread group
0278: * argument or one of its ancestor thread groups;
0279: * <code>false</code> otherwise.
0280: * @since JDK1.0
0281: */
0282: public final boolean parentOf(ThreadGroup g) {
0283: for (; g != null; g = g.parent) {
0284: if (g == this ) {
0285: return true;
0286: }
0287: }
0288: return false;
0289: }
0290:
0291: /**
0292: * Determines if the currently running thread has permission to
0293: * modify this thread group.
0294: * <p>
0295: * If there is a security manager, its <code>checkAccess</code> method
0296: * is called with this thread group as its argument. This may result
0297: * in throwing a <code>SecurityException</code>.
0298: *
0299: * @exception SecurityException if the current thread is not allowed to
0300: * access this thread group.
0301: * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
0302: * @since JDK1.0
0303: */
0304: public final void checkAccess() {
0305: SecurityManager security = System.getSecurityManager();
0306: if (security != null) {
0307: security.checkAccess(this );
0308: }
0309: }
0310:
0311: /**
0312: * Returns an estimate of the number of active threads in this
0313: * thread group.
0314: *
0315: * @return the number of active threads in this thread group and in any
0316: * other thread group that has this thread group as an ancestor.
0317: * @since JDK1.0
0318: */
0319: public int activeCount() {
0320: int result;
0321: // Snapshot sub-group data so we don't hold this lock
0322: // while our children are computing.
0323: int ngroupsSnapshot;
0324: ThreadGroup[] groupsSnapshot;
0325: synchronized (this ) {
0326: if (destroyed) {
0327: return 0;
0328: }
0329: result = nthreads;
0330: ngroupsSnapshot = ngroups;
0331: if (groups != null) {
0332: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0333: System.arraycopy(groups, 0, groupsSnapshot, 0,
0334: ngroupsSnapshot);
0335: } else {
0336: groupsSnapshot = null;
0337: }
0338: }
0339: for (int i = 0; i < ngroupsSnapshot; i++) {
0340: result += groupsSnapshot[i].activeCount();
0341: }
0342: return result;
0343: }
0344:
0345: /**
0346: * Copies into the specified array every active thread in this
0347: * thread group and its subgroups.
0348: * <p>
0349: * First, the <code>checkAccess</code> method of this thread group is
0350: * called with no arguments; this may result in a security exception.
0351: * <p>
0352: * An application should use the <code>activeCount</code> method to
0353: * get an estimate of how big the array should be. If the array is
0354: * too short to hold all the threads, the extra threads are silently
0355: * ignored.
0356: *
0357: * @param list an array into which to place the list of threads.
0358: * @return the number of threads put into the array.
0359: * @exception SecurityException if the current thread does not
0360: * have permission to enumerate this thread group.
0361: * @see java.lang.ThreadGroup#activeCount()
0362: * @see java.lang.ThreadGroup#checkAccess()
0363: * @since JDK1.0
0364: */
0365: public int enumerate(Thread list[]) {
0366: checkAccess();
0367: return enumerate(list, 0, true);
0368: }
0369:
0370: /**
0371: * Copies into the specified array every active thread in this
0372: * thread group. If the <code>recurse</code> flag is
0373: * <code>true</code>, references to every active thread in this
0374: * thread's subgroups are also included. If the array is too short to
0375: * hold all the threads, the extra threads are silently ignored.
0376: * <p>
0377: * First, the <code>checkAccess</code> method of this thread group is
0378: * called with no arguments; this may result in a security exception.
0379: * <p>
0380: * An application should use the <code>activeCount</code> method to
0381: * get an estimate of how big the array should be.
0382: *
0383: * @param list an array into which to place the list of threads.
0384: * @param recurse a flag indicating whether also to include threads
0385: * in thread groups that are subgroups of this
0386: * thread group.
0387: * @return the number of threads placed into the array.
0388: * @exception SecurityException if the current thread does not
0389: * have permission to enumerate this thread group.
0390: * @see java.lang.ThreadGroup#activeCount()
0391: * @see java.lang.ThreadGroup#checkAccess()
0392: * @since JDK1.0
0393: */
0394: public int enumerate(Thread list[], boolean recurse) {
0395: checkAccess();
0396: return enumerate(list, 0, recurse);
0397: }
0398:
0399: private int enumerate(Thread list[], int n, boolean recurse) {
0400: int ngroupsSnapshot = 0;
0401: ThreadGroup[] groupsSnapshot = null;
0402: synchronized (this ) {
0403: if (destroyed) {
0404: return 0;
0405: }
0406: int nt = nthreads;
0407: if (nt > list.length - n) {
0408: nt = list.length - n;
0409: }
0410: for (int i = 0; i < nt; i++) {
0411: if (threads[i].isAlive()) {
0412: list[n++] = threads[i];
0413: }
0414: }
0415: if (recurse) {
0416: ngroupsSnapshot = ngroups;
0417: if (groups != null) {
0418: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0419: System.arraycopy(groups, 0, groupsSnapshot, 0,
0420: ngroupsSnapshot);
0421: } else {
0422: groupsSnapshot = null;
0423: }
0424: }
0425: }
0426: if (recurse) {
0427: for (int i = 0; i < ngroupsSnapshot; i++) {
0428: n = groupsSnapshot[i].enumerate(list, n, true);
0429: }
0430: }
0431: return n;
0432: }
0433:
0434: /**
0435: * Returns an estimate of the number of active groups in this
0436: * thread group.
0437: *
0438: * @return the number of active thread groups with this thread group as
0439: * an ancestor.
0440: * @since JDK1.0
0441: */
0442: public int activeGroupCount() {
0443: int ngroupsSnapshot;
0444: ThreadGroup[] groupsSnapshot;
0445: synchronized (this ) {
0446: if (destroyed) {
0447: return 0;
0448: }
0449: ngroupsSnapshot = ngroups;
0450: if (groups != null) {
0451: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0452: System.arraycopy(groups, 0, groupsSnapshot, 0,
0453: ngroupsSnapshot);
0454: } else {
0455: groupsSnapshot = null;
0456: }
0457: }
0458: int n = ngroupsSnapshot;
0459: for (int i = 0; i < ngroupsSnapshot; i++) {
0460: n += groupsSnapshot[i].activeGroupCount();
0461: }
0462: return n;
0463: }
0464:
0465: /**
0466: * Copies into the specified array references to every active
0467: * subgroup in this thread group.
0468: * <p>
0469: * First, the <code>checkAccess</code> method of this thread group is
0470: * called with no arguments; this may result in a security exception.
0471: * <p>
0472: * An application should use the <code>activeGroupCount</code>
0473: * method to get an estimate of how big the array should be. If the
0474: * array is too short to hold all the thread groups, the extra thread
0475: * groups are silently ignored.
0476: *
0477: * @param list an array into which to place the list of thread groups.
0478: * @return the number of thread groups put into the array.
0479: * @exception SecurityException if the current thread does not
0480: * have permission to enumerate this thread group.
0481: * @see java.lang.ThreadGroup#activeGroupCount()
0482: * @see java.lang.ThreadGroup#checkAccess()
0483: * @since JDK1.0
0484: */
0485: public int enumerate(ThreadGroup list[]) {
0486: checkAccess();
0487: return enumerate(list, 0, true);
0488: }
0489:
0490: /**
0491: * Copies into the specified array references to every active
0492: * subgroup in this thread group. If the <code>recurse</code> flag is
0493: * <code>true</code>, references to all active subgroups of the
0494: * subgroups and so forth are also included.
0495: * <p>
0496: * First, the <code>checkAccess</code> method of this thread group is
0497: * called with no arguments; this may result in a security exception.
0498: * <p>
0499: * An application should use the <code>activeGroupCount</code>
0500: * method to get an estimate of how big the array should be.
0501: *
0502: * @param list an array into which to place the list of threads.
0503: * @param recurse a flag indicating whether to recursively enumerate
0504: * all included thread groups.
0505: * @return the number of thread groups put into the array.
0506: * @exception SecurityException if the current thread does not
0507: * have permission to enumerate this thread group.
0508: * @see java.lang.ThreadGroup#activeGroupCount()
0509: * @see java.lang.ThreadGroup#checkAccess()
0510: * @since JDK1.0
0511: */
0512: public int enumerate(ThreadGroup list[], boolean recurse) {
0513: checkAccess();
0514: return enumerate(list, 0, recurse);
0515: }
0516:
0517: private int enumerate(ThreadGroup list[], int n, boolean recurse) {
0518: int ngroupsSnapshot = 0;
0519: ThreadGroup[] groupsSnapshot = null;
0520: synchronized (this ) {
0521: if (destroyed) {
0522: return 0;
0523: }
0524: int ng = ngroups;
0525: if (ng > list.length - n) {
0526: ng = list.length - n;
0527: }
0528: if (ng > 0) {
0529: System.arraycopy(groups, 0, list, n, ng);
0530: n += ng;
0531: }
0532: if (recurse) {
0533: ngroupsSnapshot = ngroups;
0534: if (groups != null) {
0535: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0536: System.arraycopy(groups, 0, groupsSnapshot, 0,
0537: ngroupsSnapshot);
0538: } else {
0539: groupsSnapshot = null;
0540: }
0541: }
0542: }
0543: if (recurse) {
0544: for (int i = 0; i < ngroupsSnapshot; i++) {
0545: n = groupsSnapshot[i].enumerate(list, n, true);
0546: }
0547: }
0548: return n;
0549: }
0550:
0551: /**
0552: * Stops all threads in this thread group.
0553: * <p>
0554: * First, the <code>checkAccess</code> method of this thread group is
0555: * called with no arguments; this may result in a security exception.
0556: * <p>
0557: * This method then calls the <code>stop</code> method on all the
0558: * threads in this thread group and in all of its subgroups.
0559: *
0560: * exception SecurityException if the current thread is not allowed
0561: * to access this thread group or any of the threads in
0562: * the thread group.
0563: * see java.lang.SecurityException
0564: * see java.lang.Thread#stop()
0565: * see java.lang.ThreadGroup#checkAccess()
0566: * since JDK1.0
0567: * deprecated This method is inherently unsafe. See
0568: * {link Thread#stop} for details.
0569: *
0570: public final void stop() {
0571: if (stopOrSuspend(false))
0572: Thread.currentThread().stop();
0573: }
0574: */
0575:
0576: /**
0577: * Interrupts all threads in this thread group.
0578: * <p>
0579: * First, the <code>checkAccess</code> method of this thread group is
0580: * called with no arguments; this may result in a security exception.
0581: * <p>
0582: * This method then calls the <code>interrupt</code> method on all the
0583: * threads in this thread group and in all of its subgroups.
0584: *
0585: * @exception SecurityException if the current thread is not allowed
0586: * to access this thread group or any of the threads in
0587: * the thread group.
0588: * @see java.lang.Thread#interrupt()
0589: * @see java.lang.SecurityException
0590: * @see java.lang.ThreadGroup#checkAccess()
0591: * @since 1.2
0592: */
0593: public final void interrupt() {
0594: int ngroupsSnapshot;
0595: ThreadGroup[] groupsSnapshot;
0596: synchronized (this ) {
0597: checkAccess();
0598: for (int i = 0; i < nthreads; i++) {
0599: threads[i].interrupt();
0600: }
0601: ngroupsSnapshot = ngroups;
0602: if (groups != null) {
0603: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0604: System.arraycopy(groups, 0, groupsSnapshot, 0,
0605: ngroupsSnapshot);
0606: } else {
0607: groupsSnapshot = null;
0608: }
0609: }
0610: for (int i = 0; i < ngroupsSnapshot; i++) {
0611: groupsSnapshot[i].interrupt();
0612: }
0613: }
0614:
0615: /**
0616: * Suspends all threads in this thread group.
0617: * <p>
0618: * First, the <code>checkAccess</code> method of this thread group is
0619: * called with no arguments; this may result in a security exception.
0620: * <p>
0621: * This method then calls the <code>suspend</code> method on all the
0622: * threads in this thread group and in all of its subgroups.
0623: *
0624: * exception SecurityException if the current thread is not allowed
0625: * to access this thread group or any of the threads in
0626: * the thread group.
0627: * see java.lang.Thread#suspend()
0628: * see java.lang.SecurityException
0629: * see java.lang.ThreadGroup#checkAccess()
0630: * since JDK1.0
0631: * deprecated This method is inherently deadlock-prone. See
0632: * {link Thread#suspend} for details.
0633: *
0634: public final void suspend() {
0635: if (stopOrSuspend(true))
0636: Thread.currentThread().suspend();
0637: }
0638: */
0639:
0640: /**
0641: * Helper method: recursively stops or suspends (as directed by the
0642: * boolean argument) all of the threads in this thread group and its
0643: * subgroups, except the current thread. This method returns true
0644: * if (and only if) the current thread is found to be in this thread
0645: * group or one of its subgroups.
0646: *
0647: private boolean stopOrSuspend(boolean suspend) {
0648: boolean suicide = false;
0649: Thread us = Thread.currentThread();
0650: int ngroupsSnapshot;
0651: ThreadGroup[] groupsSnapshot = null;
0652: synchronized (this) {
0653: checkAccess();
0654: for (int i = 0 ; i < nthreads ; i++) {
0655: if (threads[i]==us)
0656: suicide = true;
0657: else if (suspend)
0658: threads[i].suspend();
0659: else
0660: threads[i].stop();
0661: }
0662:
0663: ngroupsSnapshot = ngroups;
0664: if (groups != null) {
0665: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0666: System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
0667: }
0668: }
0669: for (int i = 0 ; i < ngroupsSnapshot ; i++)
0670: suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
0671:
0672: return suicide;
0673: }
0674: */
0675:
0676: /**
0677: * Resumes all threads in this thread group.
0678: * <p>
0679: * First, the <code>checkAccess</code> method of this thread group is
0680: * called with no arguments; this may result in a security exception.
0681: * <p>
0682: * This method then calls the <code>resume</code> method on all the
0683: * threads in this thread group and in all of its sub groups.
0684: *
0685: * exception SecurityException if the current thread is not allowed to
0686: * access this thread group or any of the threads in the
0687: * thread group.
0688: * see java.lang.SecurityException
0689: * see java.lang.Thread#resume()
0690: * see java.lang.ThreadGroup#checkAccess()
0691: * since JDK1.0
0692: * deprecated This method is used solely in conjunction with
0693: * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
0694: * both of which have been deprecated, as they are inherently
0695: * deadlock-prone. See {@link Thread#suspend} for details.
0696: *
0697: public final void resume() {
0698: int ngroupsSnapshot;
0699: ThreadGroup[] groupsSnapshot;
0700: synchronized (this) {
0701: checkAccess();
0702: for (int i = 0 ; i < nthreads ; i++) {
0703: threads[i].resume();
0704: }
0705: ngroupsSnapshot = ngroups;
0706: if (groups != null) {
0707: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0708: System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
0709: } else {
0710: groupsSnapshot = null;
0711: }
0712: }
0713: for (int i = 0 ; i < ngroupsSnapshot ; i++) {
0714: groupsSnapshot[i].resume();
0715: }
0716: }
0717: */
0718:
0719: /**
0720: * Destroys this thread group and all of its subgroups. This thread
0721: * group must be empty, indicating that all threads that had been in
0722: * this thread group have since stopped.
0723: * <p>
0724: * First, the <code>checkAccess</code> method of this thread group is
0725: * called with no arguments; this may result in a security exception.
0726: *
0727: * @exception IllegalThreadStateException if the thread group is not
0728: * empty or if the thread group has already been destroyed.
0729: * @exception SecurityException if the current thread cannot modify this
0730: * thread group.
0731: * @see java.lang.ThreadGroup#checkAccess()
0732: * @since JDK1.0
0733: */
0734: public final void destroy() {
0735: int ngroupsSnapshot;
0736: ThreadGroup[] groupsSnapshot;
0737: synchronized (this ) {
0738: checkAccess();
0739: if (destroyed || (nthreads > 0)) {
0740: throw new IllegalThreadStateException();
0741: }
0742: ngroupsSnapshot = ngroups;
0743: if (groups != null) {
0744: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0745: System.arraycopy(groups, 0, groupsSnapshot, 0,
0746: ngroupsSnapshot);
0747: } else {
0748: groupsSnapshot = null;
0749: }
0750: if (parent != null) {
0751: destroyed = true;
0752: ngroups = 0;
0753: groups = null;
0754: nthreads = 0;
0755: threads = null;
0756: }
0757: }
0758: for (int i = 0; i < ngroupsSnapshot; i += 1) {
0759: groupsSnapshot[i].destroy();
0760: }
0761: if (parent != null) {
0762: parent.remove(this );
0763: }
0764: }
0765:
0766: /**
0767: * Adds the specified Thread group to this group.
0768: * @param g the specified Thread group to be added
0769: * @exception IllegalThreadStateException If the Thread group has been destroyed.
0770: */
0771: private final void add(ThreadGroup g) {
0772: synchronized (this ) {
0773: if (destroyed) {
0774: throw new IllegalThreadStateException();
0775: }
0776: if (groups == null) {
0777: groups = new ThreadGroup[4];
0778: } else if (ngroups == groups.length) {
0779: ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
0780: System.arraycopy(groups, 0, newgroups, 0, ngroups);
0781: groups = newgroups;
0782: }
0783: groups[ngroups] = g;
0784:
0785: // This is done last so it doesn't matter in case the
0786: // thread is killed
0787: ngroups++;
0788: }
0789: }
0790:
0791: /**
0792: * Removes the specified Thread group from this group.
0793: * @param g the Thread group to be removed
0794: * @return if this Thread has already been destroyed.
0795: */
0796: private void remove(ThreadGroup g) {
0797: synchronized (this ) {
0798: if (destroyed) {
0799: return;
0800: }
0801: for (int i = 0; i < ngroups; i++) {
0802: if (groups[i] == g) {
0803: if (i < --ngroups) { // if not the last active entry
0804: // slide remaining active entries 1 slot to left
0805: System.arraycopy(groups, i + 1, groups, i,
0806: ngroups - i);
0807: }
0808: // Clear vacated entry for GC.
0809: groups[ngroups] = null;
0810: break;
0811: }
0812: }
0813: if (nthreads == 0) {
0814: notifyAll();
0815: }
0816: if (daemon && (nthreads == 0) && (nUnstartedThreads == 0)
0817: && (ngroups == 0)) {
0818: destroy();
0819: }
0820: }
0821: }
0822:
0823: /**
0824: * Increments the count of unstarted threads in the thread group.
0825: * Unstarted threads are not added to the thread group so that they
0826: * can be collected if they are never started, but they must be
0827: * counted so that daemon thread groups with unstarted threads in
0828: * them are not destroyed.
0829: */
0830: void addUnstarted() {
0831: synchronized (this ) {
0832: if (destroyed) {
0833: throw new IllegalThreadStateException();
0834: }
0835: nUnstartedThreads++;
0836: }
0837: }
0838:
0839: /**
0840: * Adds the specified Thread to this group.
0841: * @param t the Thread to be added
0842: * @exception IllegalThreadStateException If the Thread group has been destroyed.
0843: */
0844: void add(Thread t) {
0845: synchronized (this ) {
0846: if (destroyed) {
0847: throw new IllegalThreadStateException();
0848: }
0849: if (threads == null) {
0850: threads = new Thread[4];
0851: } else if (nthreads == threads.length) {
0852: Thread newthreads[] = new Thread[nthreads * 2];
0853: System.arraycopy(threads, 0, newthreads, 0, nthreads);
0854: threads = newthreads;
0855: }
0856: threads[nthreads] = t;
0857:
0858: // This is done last so it doesn't matter in case the
0859: // thread is killed
0860: nthreads++;
0861: nUnstartedThreads--;
0862: }
0863: }
0864:
0865: /**
0866: * Removes the specified Thread from this group.
0867: * @param t the Thread to be removed
0868: * @return if the Thread has already been destroyed.
0869: */
0870: void remove(Thread t) {
0871: synchronized (this ) {
0872: if (destroyed) {
0873: return;
0874: }
0875: for (int i = 0; i < nthreads; i++) {
0876: if (threads[i] == t) {
0877: if (i < --nthreads) { // if not the last active entry
0878: // slide remaining active entries 1 slot to left
0879: System.arraycopy(threads, i + 1, threads, i,
0880: nthreads - i);
0881: }
0882: // Clear the vacated entry
0883: threads[nthreads] = null;
0884: break;
0885: }
0886: }
0887: if (nthreads == 0) {
0888: notifyAll();
0889: }
0890: if (daemon && (nthreads == 0) && (nUnstartedThreads == 0)
0891: && (ngroups == 0)) {
0892: destroy();
0893: }
0894: }
0895: }
0896:
0897: /**
0898: * Prints information about this thread group to the standard
0899: * output. This method is useful only for debugging.
0900: *
0901: * @since JDK1.0
0902: */
0903: public void list() {
0904: list(System.out, 0);
0905: }
0906:
0907: void list(PrintStream out, int indent) {
0908: int ngroupsSnapshot;
0909: ThreadGroup[] groupsSnapshot;
0910: synchronized (this ) {
0911: for (int j = 0; j < indent; j++) {
0912: out.print(" ");
0913: }
0914: out.println(this );
0915: indent += 4;
0916: for (int i = 0; i < nthreads; i++) {
0917: for (int j = 0; j < indent; j++) {
0918: out.print(" ");
0919: }
0920: out.println(threads[i]);
0921: }
0922: ngroupsSnapshot = ngroups;
0923: if (groups != null) {
0924: groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
0925: System.arraycopy(groups, 0, groupsSnapshot, 0,
0926: ngroupsSnapshot);
0927: } else {
0928: groupsSnapshot = null;
0929: }
0930: }
0931: for (int i = 0; i < ngroupsSnapshot; i++) {
0932: groupsSnapshot[i].list(out, indent);
0933: }
0934: }
0935:
0936: /**
0937: * Called by the Java Virtual Machine when a thread in this
0938: * thread group stops because of an uncaught exception.
0939: * <p>
0940: * The <code>uncaughtException</code> method of
0941: * <code>ThreadGroup</code> does the following:
0942: * <ul>
0943: * <li>If this thread group has a parent thread group, the
0944: * <code>uncaughtException</code> method of that parent is called
0945: * with the same two arguments.
0946: * <li>Otherwise, this method determines if the <code>Throwable</code>
0947: * argument is an instance of <code>ThreadDeath</code>. If so, nothing
0948: * special is done. Otherwise, the <code>Throwable</code>'s
0949: * <code>printStackTrace</code> method is called to print a stack
0950: * backtrace to the standard error stream.
0951: * </ul>
0952: * <p>
0953: * Applications can override this method in subclasses of
0954: * <code>ThreadGroup</code> to provide alternative handling of
0955: * uncaught exceptions.
0956: *
0957: * @param t the thread that is about to exit.
0958: * @param e the uncaught exception.
0959: * @see java.lang.System#err
0960: * @see java.lang.ThreadDeath
0961: * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
0962: * @since JDK1.0
0963: */
0964: public void uncaughtException(Thread t, Throwable e) {
0965: if (parent != null) {
0966: parent.uncaughtException(t, e);
0967: } else if (!(e instanceof ThreadDeath)) {
0968: if (System.err != null) { /* can be null at startup */
0969: e.printStackTrace(System.err);
0970: }
0971: }
0972: }
0973:
0974: /**
0975: * Used by VM to control lowmem implicit suspension.
0976: *
0977: * param b boolean to allow or disallow suspension
0978: * return true on success
0979: * since JDK1.1
0980: * deprecated The definition of this call depends on {@link #suspend},
0981: * which is deprecated. Further, the behavior of this call
0982: * was never specified.
0983: *
0984: public boolean allowThreadSuspension(boolean b) {
0985: this.vmAllowSuspension = b;
0986: if (!b) {
0987: VM.unsuspendSomeThreads();
0988: }
0989: return true;
0990: }
0991: */
0992:
0993: /**
0994: * Returns a string representation of this Thread group.
0995: *
0996: * @return a string representation of this thread group.
0997: * @since JDK1.0
0998: */
0999: public String toString() {
1000: return getClass().getName() + "[name=" + getName() + ",maxpri="
1001: + maxPriority + "]";
1002: }
1003: }
|