Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
My previous three articles explored an assortment of thread concepts: the Thread class, the Runnable interface, exceptions and the run() method, synchronization, thread scheduling, the wait/notify mechanism, and thread interruption. This month's Java 101 concludes the thread series by focusing on thread groups, volatility, thread-local variables, timers, and the ThreadDeath class. Want more on threads? The sidebar "Finalization and Threads" describes how various thread concepts combine to finalize objects.
Read the whole series on thread programming:
In a network server program, one thread waits for and accepts requests from client programs to execute, for example, database
transactions or complex calculations. The thread usually creates a new thread to handle the request. Depending on the request
volume, many different threads might be simultaneously present, complicating thread management. To simplify thread management,
programs organize their threads with thread groups—java.lang.ThreadGroup objects that group related threads' Thread (and Thread subclass) objects. For example, your program can use ThreadGroup to group all printing threads into one group.
| Note |
|---|
To keep the discussion simple, I refer to thread groups as if they organize threads. In reality, thread groups organize Thread (and Thread subclass) objects associated with threads.
|
Java requires every thread and every thread group—save the root thread group, system—to join some other thread group. That arrangement leads to a hierarchical thread-group structure, which the figure below
illustrates in an application context.

An application's hierarchical thread-group structure begins with a main thread group just below the system thread group
At the top of the figure's structure is the system thread group. The JVM-created system group organizes JVM threads that deal with object finalization and other system tasks, and serves as the root thread group
of an application's hierarchical thread-group structure. Just below system is the JVM-created main thread group, which is system's subthread group (subgroup, for short). main contains at least one thread—the JVM-created main thread that executes byte-code instructions in the main() method.
Below the main group reside the subgroup 1 and subgroup 2 subgroups, application-created subgroups (which the figure's application creates). Furthermore, subgroup 1 groups three application-created threads: thread 1, thread 2, and thread 3. In contrast, subgroup 2 groups one application-created thread: my thread.
Now that you know the basics, let's start creating thread groups.
The ThreadGroup class's SDK documentation reveals two constructors: ThreadGroup(String name) and ThreadGroup(ThreadGroup parent, String name). Both constructors create a thread group and give it a name, as the name parameter specifies. The constructors differ in their choice of what thread group serves as parent to the newly created thread
group. Each thread group, except system, must have a parent thread group. For ThreadGroup(String name), the parent is the thread group of the thread that calls ThreadGroup(String name). As an example, if the main thread calls ThreadGroup(String name), the newly created thread group has the main thread's group as its parent—main. For ThreadGroup(ThreadGroup parent, String name), the parent is the group that parent references. The following code shows how to use these constructors to create a pair of thread groups:
public static void main (String [] args)
{
ThreadGroup tg1 = new ThreadGroup ("A");
ThreadGroup tg2 = new ThreadGroup (tg1, "B");
}
In the code above, the main thread creates two thread groups: A and B. First, the main thread creates A by calling ThreadGroup(String name). The tg1-referenced thread group's parent is main because main is the main thread's thread group. Second, the main thread creates B by calling ThreadGroup(ThreadGroup parent, String name). The tg2-referenced thread group's parent is A because tg1's reference passes as an argument to ThreadGroup (tg1, "B") and A associates with tg1.
| Tip |
|---|
Once you no longer need a hierarchy of ThreadGroup objects, call ThreadGroup's void destroy() method via a reference to the ThreadGroup object at the top of that hierarchy. If the top ThreadGroup object and all subgroup objects lack thread objects, destroy() prepares those thread group objects for garbage collection. Otherwise, destroy() throws an IllegalThreadStateException object. However, until you nullify the reference to the top ThreadGroup object (assuming a field variable contains that reference), the garbage collector cannot collect that object. Referencing
the top object, you can determine if a previous call was made to the destroy() method by calling ThreadGroup's boolean isDestroyed() method. That method returns true if the thread group hierarchy was destroyed.
|
By themselves, thread groups are useless. To be of any use, they must group threads. You group threads into thread groups
by passing ThreadGroup references to appropriate Thread constructors:
ThreadGroup tg = new ThreadGroup ("subgroup 2");
Thread t = new Thread (tg, "my thread");
The code above first creates a subgroup 2 group with main as the parent group. (I assume the main thread executes the code.) The code next creates a my thread Thread object in the subgroup 2 group.
Now, let's create an application that produces our figure's hierarchical thread-group structure:
Listing 1: ThreadGroupDemo.java
// ThreadGroupDemo.java
class ThreadGroupDemo
{
public static void main (String [] args)
{
ThreadGroup tg = new ThreadGroup ("subgroup 1");
Thread t1 = new Thread (tg, "thread 1");
Thread t2 = new Thread (tg, "thread 2");
Thread t3 = new Thread (tg, "thread 3");
tg = new ThreadGroup ("subgroup 2");
Thread t4 = new Thread (tg, "my thread");
tg = Thread.currentThread ().getThreadGroup ();
int agc = tg.activeGroupCount ();
System.out.println ("Active thread groups in " + tg.getName () +
" thread group: " + agc);
tg.list ();
}
}
ThreadGroupDemo creates the appropriate thread group and thread objects to mirror what you see in the figure above. To prove that the subgroup 1 and subgroup 2 groups are main's only subgroups, ThreadGroupDemo does the following:
ThreadGroup object by calling Thread's static currentThread() method (which returns a reference to the main thread's Thread object) followed by Thread's ThreadGroup getThreadGroup() method.
ThreadGroup's int activeGroupCount() method on the just-returned ThreadGroup reference to return an estimate of active groups within the main thread's thread group.
ThreadGroup's String getName () method to return the main thread's thread group name.
ThreadGroup's void list () method to print on the standard output device details on the main thread's thread group and all subgroups.
When run, ThreadGroupDemo displays the following output:
Active thread groups in main thread group: 2
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Thread-0,5,main]
java.lang.ThreadGroup[name=subgroup 1,maxpri=10]
Thread[thread 1,5,subgroup 1]
Thread[thread 2,5,subgroup 1]
Thread[thread 3,5,subgroup 1]
java.lang.ThreadGroup[name=subgroup 2,maxpri=10]
Thread[my thread,5,subgroup 2]
Output that begins with Thread results from list()'s internal calls to Thread's toString() method, an output format I described in Part 1. Along with that output, you see output beginning with java.lang.ThreadGroup. That output identifies the thread group's name followed by its maximum priority.
A thread group's maximum priority is the highest priority any of its threads can attain. Consider the aforementioned network server program. Within that program, a thread waits for and accepts requests from client programs. Before doing that, the wait-for/accept-request thread might first create a thread group with a maximum priority just below that thread's priority. Later, when a request arrives, the wait-for/accept-request thread creates a new thread to respond to the client request and adds the new thread to the previously created thread group. The new thread's priority automatically lowers to the thread group's maximum. That way, the wait-for/accept-request thread responds more often to requests because it runs more often.
Java assigns a maximum priority to each thread group. When you create a group, Java obtains that priority from its parent
group. Use ThreadGroup's void setMaxPriority(int priority) method to subsequently set the maximum priority. Any threads that you add to the group after setting its maximum priority
cannot have a priority that exceeds the maximum. Any thread with a higher priority automatically lowers when it joins the
thread group. However, if you use setMaxPriority(int priority) to lower a group's maximum priority, all threads added to the group prior to that method call keep their original priorities.
For example, if you add a priority 8 thread to a maximum priority 9 group, and then lower that group's maximum priority to
7, the priority 8 thread remains at priority 8. At any time, you can determine a thread group's maximum priority by calling
ThreadGroup's int getMaxPriority() method. To demonstrate priority and thread groups, I wrote MaxPriorityDemo:
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq