Thread Groups

The THReadGroup class allows us to deal with threads wholesale: we can use it to arrange threads in groups and deal with the groups as a whole. A thread group can contain other thread groups, in addition to individual threads, so our arrangements can be hierarchical. Thread groups are particularly useful when we want to start a task that might create many threads of its own. By assigning the task a thread group, we can later identify and control all the task's threads. Thread groups are also the subject of restrictions that can be imposed by the Java Security Manager, so we can restrict a thread's behavior according to its thread group. For example, we can forbid threads in a particular group from interacting with threads in other groups. This is one way web browsers can prevent threads started by Java applets from stopping important system threads. When we create a thread, it normally becomes part of the thread group to which the currently running thread belongs. To create a new thread group of our own, we can call the constructor:

 ThreadGroup
 myTaskGroup = new ThreadGroup("My Task Group");


The THReadGroup constructor takes a name, which a debugger can use to help you identify the group. (You can also assign names to the threads themselves.) Once we have a group, we can put threads in the group by supplying the ThreadGroup object as an argument to the Thread constructor:

 Thread myTask = new Thread( myTaskGroup, taskPerformer );


Here, myTaskGroup is the thread group, and taskPerformer is the target object (the Runnable object that performs the task). Any additional threads that myTask creates also belong to the myTaskGroup tHRead group.

Working with ThreadGroups

The ThreadGroup class exists so that you can control threads in batches. It has methods that parallel the basic THRead control methodseven the deprecated stop( ), suspend( ), and resume( ). These methods operate on all the threads in a thread group. You can also mark a thread group as a "daemon"; a daemon thread group is automatically removed when all its children are gone. If a thread group isn't a daemon, you have to call destroy( ) to remove it when it is empty. We can set the maximum priority for threads created in a thread group by calling setMaximumPriority( ). Thereafter, no threads can be created in the thread group with a priority higher than the maximum; threads that change their priority can't set their new priority higher than the maximum. Finally, you can get a list of all threads in a group. The method activeCount( ) tells you how many threads are in the group; the method enumerate( ) gives you a list of them. We used the enumerate( ) method earlier when we showed the state of all threads in the default thread group using the static Thread.enumerate( )method. The argument to enumerate( ) is an array of Threads, which enumerate( ) fills in with the group's threads. Both activeCount( ) and enumerate( ) operate recursively on all thread groups the group contains.

Uncaught Exceptions

In Java, unchecked exceptions that are not caught by any method eventually bubble up to the run( ) method of the running thread and are thrown from there. By default, Java deals with these by simply printing them to the system error stream or log and terminating the thread. However, you can specify your own "catch all" behavior for these exceptions by subclassing ThreadGroup and overriding the uncaughtException( ) method. When an uncaught exception is generated, it is handed to this method, which can take some action or throw it again before the thread terminates. In Java 5.0, this pattern was extended by defining an interface: THRead.UncaughtExceptionHandler and adding both per-thread and systemwide uncaught exception handlers in addition to the per-ThreadGroup exception handler. We can handle uncaught exceptions for a single thread like this:

 Thread thread = new Thread( );
 thread.setUncaughtExceptionHandler(
 new Thread.UncaughtExceptionHandler( ) {
 public void uncaughtException( Thread t, Throwable e ) {
 System.err.println( t + " threw exception: " + e );
 }
 } );


This example prints the exception before the thread dies. We could have set the same handler on the ThreadGroup in the same way or assigned it for all exceptions using the static Thread.setDefaultUncaughtExceptionHandler( ) method.

Comments