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
ThreadGroup
can contain other
ThreadGroups
, 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 of the task’s threads.
ThreadGroups
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 that 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 ThreadGroup
that the currently running
thread belongs to. To create a new ThreadGroup
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 will also
belong to the myTaskGroup
thread group.
Creating thread groups isn’t interesting unless you do things
to them. The ThreadGroup
class exists so that you
can control threads in batches. It has methods that parallel the
basic Thread
control methods—even the
deprecated stop( )
,
suspend()
, and
resume( )
. These methods in the
ThreadGroup
operate on all of the threads they
contain. You can also mark a ThreadGroup
as a
“daemon”; a daemon thread group is automatically removed
when all of 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 any thread in a
ThreadGroup
by calling
setMaximumPriority( )
. Thereafter, no threads can
be created 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 of the 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. The argument to enumerate( )
is an array of
Thread
s, which enumerate()
fills in with the group’s threads. (Use activeCount( )
to make an array of the right size.) Both
activeCount()
and enumerate( )
operate recursively on all thread groups that the group contains.
It is also the responsibility of the ThreadGroup
to handle uncaught runtime exceptions thrown by the run( )
methods of its threads. You can override the
uncaughtException( )
method of
ThreadGroup
when making your own
ThreadGroup
s to control this behavior.