Note that this method will silently ignore any threads that don't fit in the * supplied array. * * @param threads the array into which the {@code Thread}s will be copied * @return the number of {@code Thread}s that were copied */ public int enumerate(Thread[] threads) { return enumerate(threads, true); } /** * Iterates over all active threads in this group (and, optionally, its * sub-groups) and stores the threads in the given array. Returns when the * array is full or no more threads remain, whichever happens first. * *
Note that this method will silently ignore any threads that don't fit in the * supplied array. * * @param threads the array into which the {@code Thread}s will be copied * @param recurse indicates whether {@code Thread}s in subgroups should be * recursively copied as well * @return the number of {@code Thread}s that were copied */ public int enumerate(Thread[] threads, boolean recurse) { return enumerateGeneric(threads, recurse, 0, true); } /** * Iterates over all thread groups in this group (and its sub-groups) and * and stores the groups in the given array. Returns when the array is full * or no more groups remain, whichever happens first. * *
Note that this method will silently ignore any thread groups that don't fit in the * supplied array. * * @param groups the array into which the {@code ThreadGroup}s will be copied * @return the number of {@code ThreadGroup}s that were copied */ public int enumerate(ThreadGroup[] groups) { return enumerate(groups, true); } /** * Iterates over all thread groups in this group (and, optionally, its * sub-groups) and stores the groups in the given array. Returns when * the array is full or no more groups remain, whichever happens first. * *
Note that this method will silently ignore any thread groups that don't fit in the
* supplied array.
*
* @param groups the array into which the {@code ThreadGroup}s will be copied
* @param recurse indicates whether {@code ThreadGroup}s in subgroups should be
* recursively copied as well or not
* @return the number of {@code ThreadGroup}s that were copied
*/
public int enumerate(ThreadGroup[] groups, boolean recurse) {
return enumerateGeneric(groups, recurse, 0, false);
}
/**
* Copies into enumeration starting at
* enumerationIndex all Threads or ThreadGroups in the
* receiver. If recurse is true, recursively enumerate the
* elements in subgroups.
*
* If the array passed as parameter is too small no exception is thrown -
* the extra elements are simply not copied.
*
* @param enumeration array into which the elements will be copied
* @param recurse Indicates whether subgroups should be enumerated or not
* @param enumerationIndex Indicates in which position of the enumeration
* array we are
* @param enumeratingThreads Indicates whether we are enumerating Threads or
* ThreadGroups
* @return How many elements were enumerated/copied over
*/
private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
boolean enumeratingThreads) {
if (enumeratingThreads) {
synchronized (threadRefs) {
// walk the references directly so we can iterate in reverse order
for (int i = threadRefs.size() - 1; i >= 0; --i) {
Thread thread = threadRefs.get(i).get();
if (thread != null && thread.isAlive()) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumeration[enumerationIndex++] = thread;
}
}
}
} else {
synchronized (groups) {
for (int i = groups.size() - 1; i >= 0; --i) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumeration[enumerationIndex++] = groups.get(i);
}
}
}
if (recurse) {
synchronized (groups) {
for (ThreadGroup group : groups) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumerationIndex = group.enumerateGeneric(enumeration, recurse,
enumerationIndex, enumeratingThreads);
}
}
}
return enumerationIndex;
}
/**
* Returns the maximum allowed priority for a {@code Thread} in this thread group.
*
* @return the maximum priority
*
* @see #setMaxPriority
*/
public final int getMaxPriority() {
return maxPriority;
}
/**
* Returns the name of this thread group.
*
* @return the group's name
*/
public final String getName() {
return name;
}
/**
* Returns this thread group's parent {@code ThreadGroup}. It can be null if this
* is the the root ThreadGroup.
*
* @return the parent
*/
public final ThreadGroup getParent() {
return parent;
}
/**
* Interrupts every {@code Thread} in this group and recursively in all its
* subgroups.
*
* @see Thread#interrupt
*/
public final void interrupt() {
synchronized (threadRefs) {
for (Thread thread : threads) {
thread.interrupt();
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
group.interrupt();
}
}
}
/**
* Checks whether this thread group is a daemon {@code ThreadGroup}.
*
* @return true if this thread group is a daemon {@code ThreadGroup}
*
* @see #setDaemon
* @see #destroy
*/
public final boolean isDaemon() {
return isDaemon;
}
/**
* Checks whether this thread group has already been destroyed.
*
* @return true if this thread group has already been destroyed
* @see #destroy
*/
public synchronized boolean isDestroyed() {
return isDestroyed;
}
/**
* Outputs to {@code System.out} a text representation of the
* hierarchy of {@code Thread}s and {@code ThreadGroup}s in this thread group (and recursively).
* Proper indentation is used to show the nesting of groups inside groups
* and threads inside groups.
*/
public void list() {
// We start in a fresh line
System.out.println();
list(0);
}
/*
* Outputs to {@code System.out}a text representation of the
* hierarchy of Threads and ThreadGroups in this thread group (and recursively).
* The indentation will be four spaces per level of nesting.
*
* @param levels How many levels of nesting, so that proper indentation can
* be output.
*/
private void list(int levels) {
indent(levels);
System.out.println(this.toString());
++levels;
synchronized (threadRefs) {
for (Thread thread : threads) {
indent(levels);
System.out.println(thread);
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
group.list(levels);
}
}
}
private void indent(int levels) {
for (int i = 0; i < levels; i++) {
System.out.print(" "); // 4 spaces for each level
}
}
/**
* Checks whether this thread group is a direct or indirect parent group of a
* given {@code ThreadGroup}.
*
* @param g the potential child {@code ThreadGroup}
* @return true if this thread group is parent of {@code g}
*/
public final boolean parentOf(ThreadGroup g) {
while (g != null) {
if (this == g) {
return true;
}
g = g.parent;
}
return false;
}
/**
* Removes an immediate subgroup.
*
* @param g ThreadGroup to remove
*
* @see #add(Thread)
* @see #add(ThreadGroup)
*/
private void remove(ThreadGroup g) {
synchronized (groups) {
for (Iterator A caller can never increase the maximum priority of a thread group.
* Such an attempt will not result in an exception, it will
* simply leave the thread group with its current maximum priority.
*
* @param newMax the new maximum priority to be set
*
* @throws IllegalArgumentException if the new priority is greater than
* Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
*
* @see #getMaxPriority
*/
public final void setMaxPriority(int newMax) {
if (newMax <= this.maxPriority) {
if (newMax < Thread.MIN_PRIORITY) {
newMax = Thread.MIN_PRIORITY;
}
int parentPriority = parent == null ? newMax : parent.getMaxPriority();
this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
synchronized (groups) {
for (ThreadGroup group : groups) {
group.setMaxPriority(newMax);
}
}
}
}
/**
* Stops every thread in this group and recursively in all its subgroups.
*
* @see Thread#stop()
* @see Thread#stop(Throwable)
* @see ThreadDeath
*
* @deprecated Requires deprecated method Thread.stop().
*/
@SuppressWarnings("deprecation")
@Deprecated
public final void stop() {
if (stopHelper()) {
Thread.currentThread().stop();
}
}
@SuppressWarnings("deprecation")
private boolean stopHelper() {
boolean stopCurrent = false;
synchronized (threadRefs) {
Thread current = Thread.currentThread();
for (Thread thread : threads) {
if (thread == current) {
stopCurrent = true;
} else {
thread.stop();
}
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
stopCurrent |= group.stopHelper();
}
}
return stopCurrent;
}
/**
* Suspends every thread in this group and recursively in all its
* subgroups.
*
* @see Thread#suspend
* @see #resume
*
* @deprecated Requires deprecated method Thread.suspend().
*/
@SuppressWarnings("deprecation")
@Deprecated
public final void suspend() {
if (suspendHelper()) {
Thread.currentThread().suspend();
}
}
@SuppressWarnings("deprecation")
private boolean suspendHelper() {
boolean suspendCurrent = false;
synchronized (threadRefs) {
Thread current = Thread.currentThread();
for (Thread thread : threads) {
if (thread == current) {
suspendCurrent = true;
} else {
thread.suspend();
}
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
suspendCurrent |= group.suspendHelper();
}
}
return suspendCurrent;
}
@Override
public String toString() {
return getClass().getName() + "[name=" + getName()
+ ",maxPriority=" + getMaxPriority() + "]";
}
/**
* Handles uncaught exceptions. Any uncaught exception in any {@code Thread}
* is forwarded to the thread's {@code ThreadGroup} by invoking this
* method.
*
* New code should use {@link Thread#setUncaughtExceptionHandler} instead of thread groups.
*
* @param t the Thread that terminated with an uncaught exception
* @param e the uncaught exception itself
*/
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else if (Thread.getDefaultUncaughtExceptionHandler() != null) {
// TODO The spec is unclear regarding this. What do we do?
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
// No parent group, has to be 'system' Thread Group
e.printStackTrace(System.err);
}
}
/**
* Called by the Thread constructor.
*/
final void addThread(Thread thread) throws IllegalThreadStateException {
synchronized (threadRefs) {
if (isDestroyed) {
throw new IllegalThreadStateException();
}
threadRefs.add(new WeakReference