The ThreadGroup class can be used to establish some thread security and authorization constraints on threads. It is also a way to group threads together so that actions can be performed on an entire set of threads. For example, you can start or stop all the threads within a ThreadGroup. After a thread is inserted into a ThreadGroup, it can't be put into a different ThreadGroup. Most Java developers don't use ThreadGroups. That is, they just create new threads and accept whatever ThreadGroup the default is and put the new thread into that group. By default, all threads that are created belong to the default ThreadGroup of the main thread or a ThreadGroup called main. This is the same ThreadGroup in which the main thread is running. Threads that belong to a particular ThreadGroup are not allowed to access or change the state of other threads that are in a different ThreadGroup. This restriction includes the parent ThreadGroup of the ThreadGroup or any other ThreadGroup that exists. The ThreadGroup class itself does not enforce this restriction, but rather relies on the SecurityManager that is installed for the running application. The ThreadGroup object works with the SecurityManager that is installed for the running application and together they determine what access is granted and what access is restricted. ThreadGroups can form trees in which one ThreadGroup can be the parent or child of another ThreadGroup. By creating a custom ThreadGroup and assigning your new threads to this ThreadGroup object, you are locking down your thread's capability to access information about other threads outside of its ThreadGroup. Caution If a thread attempts to access another thread that belongs to a different ThreadGroup and the SecurityManager has not granted this access, a SecurityException will be thrown. Take a look at an example using ThreadGroups. This example isn't too complicated, but it shows how to create a new ThreadGroup other than the default and assign threads into the group. This examples uses a thread called WorkerThread to perform some repetitive task that might need to be performed. The idea here is that there are multiple worker threads created, each one doing something for the overall application. In this case, it's just going to print out that the thread is running. This could have been something like checking a directory for a file, or listening on a socket for a request. This example is simple because the only purpose is to understand the ThreadGroups. Listing 11.15 shows the source for the WorkerThread that belongs to a ThreadGroup. Listing 11.15 Source Code for WorkerThread.javapublic class WorkerThread extends Thread { // Boolean flag that keeps state about when the thread should stop boolean keepRunning = true; // Default Constructor public WorkerThread( ThreadGroup group, String threadName ) { super( group, threadName ); } // Override the parents run method to do something special public void run() { // While the thread should keep running while( getKeepRunning() ) { System.out.println( "Thread " + getName() + " is Running" ); try { // Sleep for a time sleep( 3000 ); } catch( Exception ex ) { /* Don't do anything here */ } } // Let the user know that this thread is exiting System.out.println( "Thread: " + getName() + " is stopping" ); } // public setting method to stop the thread public synchronized void setKeepRunning( boolean trueOrFalse ) { keepRunning = trueOrFalse; } // public accessor for getting the state of this thread public synchronized boolean getKeepRunning() { return keepRunning; } } The boolean flag keepRunning is similar to the one from the synchronization section. Its used by the worker thread to know when it's time to quit. It needs to be synchronized because both the HandlerThread and the WorkerThread need to access it. The next class in this example is the handler thread that is responsible for creating the worker threads and also informing them when it's time to stop. Listing 11.16 shows the HandlerThread. The main method is located inside the HandlerThread to keep this example compact Listing 11.16 Source Code for HandlerThread.javapublic class HandlerThread extends Thread { // The default constructor for the HandlerThread public HandlerThread( ThreadGroup ownerGroup, String threadName ) { super( ownerGroup, threadName ); } // Override the parents run to do something different public void run() { // How many worker threads to start up int numberOfChildren = 3; // Declare the reference outside of the loop for better performance WorkerThread childThread = null; // Loop through and start up the worker threads for( int i = 1; i <= numberOfChildren; i++ ) { childThread = new WorkerThread( getThreadGroup(), "Thread" + String.valueOf(i) ); childThread.start(); } // Go to sleep for 3 seconds and let the worker threads do something try { sleep( 3000 ); } catch( InterruptedException ex ) { /* Don't need to handle this for now */ } // Get the thread group that I belong to ThreadGroup myGroup = getThreadGroup(); // how many active threads are in my group that I need to stop int activeEstimatedThreadCount = myGroup.activeCount(); Thread[] activeThreads = new Thread[ activeEstimatedThreadCount ]; // Get the count of active threads int activeThreadCount = myGroup.enumerate( activeThreads ); // Declare the reference outside of the loop for performance Thread thread = null; // Loop through all the active threads and signal them to quit for( int counter = 0; counter < activeThreadCount; counter++ ) { // Get one of the active threads out of the array thread = activeThreads[counter]; // Make sure it's a worker thread. There may be others active // If it is a worker thread, tell it to stop running if ( thread instanceof WorkerThread ) ((WorkerThread)thread).setKeepRunning(false); } } public static void main( String args[] ) { // Create a new ThreadGroup ThreadGroup threadGroup = new ThreadGroup( "MyNewGroup" ); // Start the handler, which will start the worker threads HandlerThread handler = new HandlerThread( threadGroup, "HandlerThread" ); // Start the handler thread running handler.start(); } } |