FileDocCategorySizeDatePackage
ThreadGroup.javaAPI DocAndroid 1.5 API31774Wed May 06 22:41:04 BST 2009java.lang

ThreadGroup

public class ThreadGroup extends Object implements Thread$UncaughtExceptionHandler
A {@code ThreadGroup} is a means of organizing {@link Thread}s into a hierarchical structure. A {@code ThreadGroup} can contain zero or more {@code Thread}s and zero or more other {@code ThreadGroup}s. Each {@code Thread} and each {@code ThreadGroup} (except the root group) has a unique parent {@code ThreadGroup}. The result is a tree whose inner nodes are {@code ThreadGroup}s and whose leaf nodes are {@code Threads}. The unique root of the tree is a {@code ThreadGroup} that is created at VM startup and has the name "system". The benefit of using {@code ThreadGroup}s, in addition to the mere housekeeping aspect, is that all {@code Thread}s in a {@code ThreadGroup} can be manipulated together, that is, the {@code ThreadGroup} has methods that delegate to all its all {@code Thread}s.
see
Thread
see
SecurityManager
since
Android 1.0

Fields Summary
private String
name
private int
maxPriority
ThreadGroup
parent
int
numThreads
private Thread[]
childrenThreads
int
numGroups
private ThreadGroup[]
childrenGroups
private Object
childrenGroupsLock
private Object
childrenThreadsLock
private boolean
isDaemon
private boolean
isDestroyed
static ThreadGroup
mSystem
static ThreadGroup
mMain
Constructors Summary
public ThreadGroup(String name)
Constructs a new ThreadGroup with the name provided. The new ThreadGroup will be child of the ThreadGroup to which the {@code Thread.currentThread()} belongs.

param
name the name for the ThreadGroup being created
throws
SecurityException if {@code checkAccess()} for the parent group fails with a SecurityException
see
java.lang.Thread#currentThread

    // END android-added

    // BEGIN android-removed
    // /**
    //  * Used by the JVM to create the "system" ThreadGroup. Construct a
    //  * ThreadGroup instance, and assign the name "system".
    //  */
    // private ThreadGroup() {
    //     name = "system";
    // }
    // END android-removed

                                                                   

       
        this(Thread.currentThread().getThreadGroup(), name);
    
public ThreadGroup(ThreadGroup parent, String name)
Constructs a new ThreadGroup with the name provided, as child of the ThreadGroup {@code parent}.

param
parent the parent ThreadGroup
param
name the name for the ThreadGroup being created
throws
NullPointerException if {@code parent} is {@code null}
throws
SecurityException if {@code checkAccess()} for the parent group fails with a SecurityException
throws
IllegalThreadStateException if {@code parent} has been destroyed already

        super();
        if (Thread.currentThread() != null) {
            // If parent is null we must throw NullPointerException, but that
            // will be done "for free" with the message send below
            parent.checkAccess();
        }

        this.name = name;
        this.setParent(parent);
        if (parent != null) {
            this.setMaxPriority(parent.getMaxPriority());
            if (parent.isDaemon()) {
                this.setDaemon(true);
            }
        }
    
ThreadGroup()
Initialize the special "system" ThreadGroup. Was "main" in Harmony, but we have an additional group above that in Android.

        this.name = "system";
        this.setParent(null); 
    
Methods Summary
public intactiveCount()
Returns the number of Threads which are children of the receiver, directly or indirectly and are running.

return
the number of children Threads

        // BEGIN android-changed
        int count = 0;
        // Lock the children thread list
        synchronized (this.childrenThreadsLock) {
            for (int i = 0; i < numThreads; i++) {
                if(childrenThreads[i].isAlive()) {
                    count++;
                }
            }
        }
        // END android-changed
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                count += this.childrenGroups[i].activeCount();
            }
        }
        return count;
    
public intactiveGroupCount()
Returns the number of ThreadGroups which are children of the receiver, directly or indirectly.

return
the number of children ThreadGroups

        int count = 0;
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                // One for this group & the subgroups
                count += 1 + this.childrenGroups[i].activeGroupCount();
            }
        }
        return count;
    
final voidadd(java.lang.Thread thread)
Adds a Thread to the receiver. This should only be visible to class java.lang.Thread, and should only be called when a new Thread is created and initialized by the constructor.

param
thread Thread to add to the receiver
throws
IllegalThreadStateException if the receiver has been destroyed already
see
#remove(java.lang.Thread)

        synchronized (this.childrenThreadsLock) {
            if (!isDestroyed) {
                if (childrenThreads.length == numThreads) {
                    Thread[] newThreads = new Thread[childrenThreads.length * 2];
                    System.arraycopy(childrenThreads, 0, newThreads, 0, numThreads);
                    newThreads[numThreads++] = thread;
                    childrenThreads = newThreads;
                } else {
                    childrenThreads[numThreads++] = thread;
                }
            } else {
                throw new IllegalThreadStateException();
            }
        }
    
private voidadd(java.lang.ThreadGroup g)
Adds a ThreadGroup to the receiver.

param
g ThreadGroup to add to the receiver
throws
IllegalThreadStateException if the receiver has been destroyed already

        synchronized (this.childrenGroupsLock) {
            if (!isDestroyed) {
                if (childrenGroups.length == numGroups) {
                    ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
                    System.arraycopy(childrenGroups, 0, newGroups, 0, numGroups);
                    newGroups[numGroups++] = g;
                    childrenGroups = newGroups;
                } else {
                    childrenGroups[numGroups++] = g;
                }
            } else {
                throw new IllegalThreadStateException();
            }
        }
    
voidaddThread(java.lang.Thread thread)
Non-standard method for adding a thread to a group, required by Dalvik.

param
thread Thread to add to the receiver
throws
IllegalThreadStateException if the receiver has been destroyed already
see
#add(java.lang.Thread)
see
#removeThread(java.lang.Thread)

        add(thread);
    
public booleanallowThreadSuspension(boolean b)
Does nothing. The definition of this method depends on the deprecated method {@link #suspend()}. The exact behavior of this call was never specified.

param
b Used to control low memory implicit suspension
return
{@code true} (always)
deprecated
Required deprecated method suspend().

        // Does not apply to this VM, no-op
        return true;
    
public final voidcheckAccess()
Checks the accessibility of the ThreadGroup from the perspective of the caller. If there is a SecurityManager installed, calls {@code checkAccess} with the receiver as a parameter, otherwise does nothing.

        // Forwards the message to the SecurityManager (if there's one) passing
        // the receiver as parameter
        SecurityManager currentManager = System.getSecurityManager();
        if (currentManager != null) {
            currentManager.checkAccess(this);
        }
    
public final voiddestroy()
Destroys the receiver and recursively all its subgroups. It is only legal to destroy a ThreadGroup that has no Threads in it. Any daemon ThreadGroup is destroyed automatically when it becomes empty (no Threads and no ThreadGroups in it).

throws
IllegalThreadStateException if the receiver or any of its subgroups has been destroyed already or if it still contains threads.
throws
SecurityException if {@code this.checkAccess()} fails with a SecurityException

        checkAccess();

        // Lock this subpart of the tree as we walk
        synchronized (this.childrenThreadsLock) {
            synchronized (this.childrenGroupsLock) {
                // BEGIN android-added
                if (this.isDestroyed) {
                    throw new IllegalThreadStateException(
                            "Thread group was already destroyed: "
                            + (this.name != null ? this.name : "n/a"));
                }
                if (this.numThreads > 0) {
                    throw new IllegalThreadStateException(
                            "Thread group still contains threads: "
                            + (this.name != null ? this.name : "n/a"));
                }
                // END android-added
                int toDestroy = numGroups;
                // Call recursively for subgroups
                for (int i = 0; i < toDestroy; i++) {
                    // We always get the first element - remember, when the
                    // child dies it removes itself from our collection. See
                    // below.
                    this.childrenGroups[0].destroy();
                }

                if (parent != null) {
                    parent.remove(this);
                }

                // Now that the ThreadGroup is really destroyed it can be tagged
                // as so
                this.isDestroyed = true;
            }
        }
    
private voiddestroyIfEmptyDaemon()

        // Has to be non-destroyed daemon to make sense
        synchronized (this.childrenThreadsLock) {
            if (isDaemon && !isDestroyed && numThreads == 0) {
                synchronized (this.childrenGroupsLock) {
                    if (numGroups == 0) {
                        destroy();
                    }
                }
            }
        }
    
public intenumerate(java.lang.Thread[] threads)
Iterates over all active threads in this group (and 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.

param
threads the array into which the Threads will be copied
return
the number of Threads that were copied

        return enumerate(threads, true);
    
public intenumerate(java.lang.Thread[] threads, boolean recurse)
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.

param
threads the array into which the Threads will be copied
param
recurse indicates whether Threads in subgroups should be recursively copied as well
return
the number of Threads that were copied

        return enumerateGeneric(threads, recurse, 0, true);
    
public intenumerate(java.lang.ThreadGroup[] groups)
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.

param
groups the array into which the ThreadGroups will be copied
return
the number of ThreadGroups that were copied

        return enumerate(groups, true);
    
public intenumerate(java.lang.ThreadGroup[] groups, boolean recurse)
Iterates over all thread groups in this group (and, optionally, 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.

param
groups the array into which the ThreadGroups will be copied
param
recurse indicates whether ThreadGroups in subgroups should be recursively copied as well or not
return
the number of ThreadGroups that were copied

        return enumerateGeneric(groups, recurse, 0, false);
    
private intenumerateGeneric(java.lang.Object[] enumeration, boolean recurse, int enumerationIndex, boolean enumeratingThreads)
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

        checkAccess();

        Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
                : (Object[]) childrenGroups;
        Object syncLock = enumeratingThreads ? childrenThreadsLock : childrenGroupsLock;

        synchronized (syncLock) { // Lock this subpart of the tree as we walk
            for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
                if (!enumeratingThreads || ((Thread) immediateCollection[i]).isAlive()) {
                    if (enumerationIndex >= enumeration.length) {
                        return enumerationIndex;
                    }
                    enumeration[enumerationIndex++] = immediateCollection[i];
                }
            }
        }

        if (recurse) { // Lock this subpart of the tree as we walk
            synchronized (this.childrenGroupsLock) {
                for (int i = 0; i < numGroups; i++) {
                    if (enumerationIndex >= enumeration.length) {
                        return enumerationIndex;
                    }
                    enumerationIndex = childrenGroups[i].enumerateGeneric(enumeration, recurse,
                            enumerationIndex, enumeratingThreads);
                }
            }
        }
        return enumerationIndex;
    
public final intgetMaxPriority()
Returns the maximum allowed priority for a Thread in the receiver.

return
the maximum priority
see
#setMaxPriority

        return maxPriority;
    
public final java.lang.StringgetName()
Returns the name of the receiver.

return
the receiver's name

        return name;
    
public final java.lang.ThreadGroupgetParent()
Returns the receiver's parent ThreadGroup. It can be {@code null} if the receiver is the the root ThreadGroup.

return
the parent ThreadGroup

        if (parent != null) {
            parent.checkAccess();
        }
        return parent;
    
public final voidinterrupt()
Interrupts every Thread in the receiver and recursively in all its subgroups.

throws
SecurityException if {@code this.checkAccess()} fails with a SecurityException
see
Thread#interrupt

        checkAccess();
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenThreadsLock) {
            for (int i = 0; i < numThreads; i++) {
                this.childrenThreads[i].interrupt();
            }
        }
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                this.childrenGroups[i].interrupt();
            }
        }
    
public final booleanisDaemon()
Checks whether the receiver is a daemon ThreadGroup.

return
true if (and only if) the receiver is a daemon ThreadGroup
see
#setDaemon
see
#destroy

        return isDaemon;
    
public synchronized booleanisDestroyed()
Checks whether the receiver has already been destroyed.

return
true if (and only if) the receiver has already been destroyed
see
#destroy

        return isDestroyed;
    
public voidlist()
Outputs to {@code System.out} a text representation of the hierarchy of Threads and ThreadGroups in the receiver (and recursively). Proper indentation is done to suggest the nesting of groups inside groups and threads inside groups.

        // We start in a fresh line
        System.out.println();
        list(0);
    
private voidlist(int levels)

        for (int i = 0; i < levels; i++) {
            System.out.print("    "); // 4 spaces for each level
        }

        // Print the receiver
        System.out.println(this.toString());

        // Print the children threads, with 1 extra indentation
        synchronized (this.childrenThreadsLock) {
            for (int i = 0; i < numThreads; i++) {
                // children get an extra indentation, 4 spaces for each level
                for (int j = 0; j <= levels; j++) {
                    System.out.print("    ");
                }
                System.out.println(this.childrenThreads[i]);
            }
        }
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                this.childrenGroups[i].list(levels + 1);
            }
        }
    
public final booleanparentOf(java.lang.ThreadGroup g)
Checks whether the receiver is a direct or indirect parent group of a given ThreadGroup.

param
g the potential child ThreadGroup
return
true if (and only if) the receiver is parent of {@code g}

        while (g != null) {
            if (this == g) {
                return true;
            }
            g = g.parent;
        }
        return false;
    
final voidremove(java.lang.Thread thread)
Removes a Thread from the receiver. This should only be visible to class java.lang.Thread, and should only be called when a Thread dies.

param
thread Thread to remove from the receiver
see
#add(Thread)

        synchronized (this.childrenThreadsLock) {
            for (int i = 0; i < numThreads; i++) {
                if (childrenThreads[i].equals(thread)) {
                    numThreads--;
                    System
                            .arraycopy(childrenThreads, i + 1, childrenThreads, i, numThreads
                                    - i);
                    childrenThreads[numThreads] = null;
                    break;
                }
            }
        }
        destroyIfEmptyDaemon();
    
private voidremove(java.lang.ThreadGroup g)
Removes an immediate subgroup from the receiver.

param
g ThreadGroup to remove from the receiver
see
#add(Thread)
see
#add(ThreadGroup)

        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                if (childrenGroups[i].equals(g)) {
                    numGroups--;
                    System.arraycopy(childrenGroups, i + 1, childrenGroups, i, numGroups - i);
                    childrenGroups[numGroups] = null;
                    break;
                }
            }
        }
        destroyIfEmptyDaemon();
    
voidremoveThread(java.lang.Thread thread)
Non-standard method for adding a thread to a group, required by Dalvik.

param
thread Thread to add to the receiver
throws
IllegalThreadStateException if the receiver has been destroyed already
see
#remove(java.lang.Thread)
see
#addThread(java.lang.Thread)

        remove(thread);
    
public final voidresume()
Resumes every Thread in the receiver and recursively in all its subgroups.

throws
SecurityException if {@code this.checkAccess()} fails with a SecurityException
see
Thread#resume
see
#suspend
deprecated
Requires deprecated method Thread.resume().

        checkAccess();
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenThreadsLock) {
            for (int i = 0; i < numThreads; i++) {
                this.childrenThreads[i].resume();
            }
        }
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                this.childrenGroups[i].resume();
            }
        }
    
public final voidsetDaemon(boolean isDaemon)
Configures the receiver to be a daemon ThreadGroup or not. Daemon ThreadGroups are automatically destroyed when they become empty.

param
isDaemon the new value defining if receiver should be daemon or not
throws
SecurityException if {@code checkAccess()} for the parent group fails with a SecurityException
see
#isDaemon
see
#destroy

        checkAccess();
        this.isDaemon = isDaemon;
    
public final voidsetMaxPriority(int newMax)
Configures the maximum allowed priority for a Thread in the receiver and recursively in all its subgroups. One can never change the maximum priority of a ThreadGroup to be higher than it was. Such an attempt will not result in an exception, it will simply leave the ThreadGroup with its current maximum priority.

param
newMax the new maximum priority to be set
throws
SecurityException if {@code checkAccess()} fails with a SecurityException
throws
IllegalArgumentException if the new priority is greater than Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
see
#getMaxPriority

        checkAccess();

        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;
            // Lock this subpart of the tree as we walk
            synchronized (this.childrenGroupsLock) {
                // ??? why not maxPriority
                for (int i = 0; i < numGroups; i++) {
                    this.childrenGroups[i].setMaxPriority(newMax);
                }
            }
        }
    
private voidsetParent(java.lang.ThreadGroup parent)
Sets the parent ThreadGroup of the receiver, and adds the receiver to the parent's collection of immediate children (if {@code parent} is not {@code null}).

param
parent The parent ThreadGroup, or null if the receiver is to be the root ThreadGroup
see
#getParent
see
#parentOf

        if (parent != null) {
            parent.add(this);
        }
        this.parent = parent;
    
public final voidstop()
Stops every Thread in the receiver and recursively in all its subgroups.

throws
SecurityException if {@code this.checkAccess()} fails with a SecurityException
see
Thread#stop()
see
Thread#stop(Throwable)
see
ThreadDeath
deprecated
Requires deprecated method Thread.stop().

        if (stopHelper()) {
            Thread.currentThread().stop();
        }
    
private final booleanstopHelper()

deprecated
Requires deprecated method Thread.suspend().

        checkAccess();

        boolean stopCurrent = false;
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenThreadsLock) {
            Thread current = Thread.currentThread();
            for (int i = 0; i < numThreads; i++) {
                if (this.childrenThreads[i] == current) {
                    stopCurrent = true;
                } else {
                    this.childrenThreads[i].stop();
                }
            }
        }
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                stopCurrent |= this.childrenGroups[i].stopHelper();
            }
        }
        return stopCurrent;
    
public final voidsuspend()
Suspends every Thread in the receiver and recursively in all its subgroups.

throws
SecurityException if {@code this.checkAccess()} fails with a SecurityException
see
Thread#suspend
see
#resume
deprecated
Requires deprecated method Thread.suspend().

        if (suspendHelper()) {
            Thread.currentThread().suspend();
        }
    
private final booleansuspendHelper()

deprecated
Requires deprecated method Thread.suspend().

        checkAccess();

        boolean suspendCurrent = false;
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenThreadsLock) {
            Thread current = Thread.currentThread();
            for (int i = 0; i < numThreads; i++) {
                if (this.childrenThreads[i] == current) {
                    suspendCurrent = true;
                } else {
                    this.childrenThreads[i].suspend();
                }
            }
        }
        // Lock this subpart of the tree as we walk
        synchronized (this.childrenGroupsLock) {
            for (int i = 0; i < numGroups; i++) {
                suspendCurrent |= this.childrenGroups[i].suspendHelper();
            }
        }
        return suspendCurrent;
    
public java.lang.StringtoString()
Returns a string containing a concise, human-readable description of the receiver.

return
a printable representation of the ThreadGroup

        return getClass().getName() + "[name=" + this.getName() + ",maxpri="
                + this.getMaxPriority() + "]";
    
public voiduncaughtException(java.lang.Thread t, java.lang.Throwable e)
Handles uncaught exceptions. Any uncaught exception in any Thread is forwarded (by the VM) to the Thread's ThreadGroup by sending this message (uncaughtException). This allows users to define custom ThreadGroup classes and custom behavior for when a Thread has an uncaughtException or when it does (ThreadDeath).

param
t the Thread that terminated with an uncaught exception
param
e the uncaught exception itself
see
Thread#stop()
see
Thread#stop(Throwable)
see
ThreadDeath

        // BEGIN android-changed
        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);
        }
        // END android-changed