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