|
This article discusses daemon threads—how they can be created within your code using the Thread.setDaemon() method and behind the scenes by the AWT. It also cautions against using them.
Have you ever wondered why it's necessary to call System.exit() to force your Java GUI application to exit?
Have a look at the following code:
| 1 |
import java.awt.*; |
| 2 |
import java.awt.event.*; |
| 3 |
|
| 4 |
public class Daemon_1 { |
| 5 |
public static void main(String[] args) { |
| 6 |
Frame f = new Frame(); |
| 7 |
|
| 8 |
f.addWindowListener(new WindowAdapter() { |
| 9 |
public void windowClosing(WindowEvent evt) { |
| 10 |
System.exit(0); |
| 11 |
} |
| 12 |
}); |
| 13 |
|
| 14 |
f.setBounds(30, 30, 400, 400); |
| 15 |
f.setVisible(true); |
| 16 |
} // main() |
| 17 |
} // Daemon_1 |
After the setVisible() method has been called at line 15, the main() method completes execution yet the window remains displayed. Isn't a program supposed to end when its main() method completes? The answer to this question is rooted in a subtlety of Java's thread creation mechanism.
Java makes a distinction between a user thread and another type of thread known as a daemon thread. The difference between these two types of threads is straightforward: If the Java runtime determines that the only threads running in an application are daemon threads (i.e., there are no user threads in existence) the Java runtime promptly closes down the application, effectively stopping all daemon threads dead in their tracks. In order for an application to continue running, it must always have at least one live user thread. In all other respects the Java runtime treats daemon threads and user threads in exactly the same manner.
When the main() method initially receives control from the Java runtime it executes in the context of a user thread. For the sake of this discussion we'll refer to this thread as the main-method thread. As long as the main-method thread (or any other user thread) remains alive the application will continue to execute. To see just how a thread becomes a daemon thread, read on.
Going to the Devil
There are two ways a thread can become a daemon thread (or a user thread, for that matter) without putting your soul at risk. First, you can explicitly specify a thread to be a daemon thread by calling setDaemon(true) on a Thread object. Note that the setDaemon() method must be called before the thread's start() method is invoked, as the following snippet shows:
| 1 |
Thread t = new Thread() { |
| 2 |
public void run() { |
| 3 |
System.out.println("I'm a man of wealth and taste..."); |
| 4 |
} |
| 5 |
}; |
| 6 |
|
| 7 |
t.setDaemon(true); |
| 8 |
t.start(); |
Once a thread has started executing (i.e., its start() method has been called) its daemon status cannot be changed.
The second technique for creating a daemon thread is based on an often overlooked feature of Java's threading behavior: If a thread creates a new thread and does not call setDaemon() to explicitlly set the new thread's "daemon status", the new thread inherits the "daemon-status" of the thread that created it. In other words, unless setDaemon(false) is called, all threads created by daemon threads will be daemon threads; similarly, unless setDaemon(true) is called, all threads created by user threads will be user threads.
Let's take a look at an example that illustrates this behavior:
| 1 |
public class Daemon_2 { |
| 2 |
public static void main(String[] args) { |
| 3 |
Thread t1 = new Thread() { |
| 4 |
public void run() { |
| 5 |
// Fire off a new thread. |
| 6 |
Thread t2 = new Thread() { |
| 7 |
public void run() { |
| 8 |
while(true) |
| 9 |
System.out.println("Pleased to meet you."); |
| 10 |
} |
| 11 |
}; // end of t2 |
| 12 |
|
| 13 |
t2.start(); |
| 14 |
System.out.println("t1 is about to end."); |
| 15 |
} |
| 16 |
}; // end of t1 |
| 17 |
|
| 18 |
// t1.setDaemon(true); |
| 19 |
t1.start(); |
| 20 |
|
| 21 |
for(int i = 0; i < 50; ++i) |
| 22 |
System.out.println("Hope you guess my name."); |
| 23 |
|
| 24 |
System.out.println("Main thread is about to end."); |
| 25 |
} // main() |
| 26 |
} // Daemon_2 |
This program creates a thread, t1, whose only purpose in life is to create and start a second thread, t2. Once this task is complete, t1 ends. t2's destiny is to print the greeting, "Pleased to meet you.", for all eternity. If you run this code you'll see that even though the main-method thread and the t1 thread have both ended, t2 goes on forever printing its message forever. This behavior is due to the fact that t2 inherited its status as a user thread from the thread that created it, t1. t1, in turn, inherited its "daemon status" from its creator, the main-method thread which, as I said, is always created by the Java runtime as a user thread.
Now, the important point: By uncommenting line 18, t1 becomes a daemon thread. When t1 then creates t2, it also becomes a daemon thread. As a result, when the main-method thread exits the Java runtime will end the entire application since only remaining thread (t2) is a daemon.
Exorcise the Daemons
Now, applying what we've learned about daemon thread creation let's consider again why it's usually necessary for a Java graphical application to call System.exit() in order to end itself.
As it turns out, the first time an application creates any java.awt.Window component (e.g., Frame, JFrame, JDialog, etc.), Java's internal AWT plumbing creates several threads behind the scenes. These AWT "plumbing threads" are responsible for handling event queue management and window re-painting. If you've done any amount of AWT or Swing development you know that a number of AWT and Swing components extend java.awt.Window either directly or indirectly. If the creation of the first java.awt.Window component occurs from within a user thread (such as the main-method thread) then these new AWT "plumbing threads" will also be user threads and therefore will not be shutdown simply because the main-method thread ends. This explains why a user interface is visible even after the main-method thread ends.
As an aside you should note that the creation of a java.awt.Window is not the only event that results in the creation of the aforementioned AWT "plumbing threads". A simple call to java.awt.Toolkit.getDefaultToolkit() will generate the creation of the background AWT threads.
Let's put what we've learned to the test. The program below creates and displays a Frame from within a daemon thread. After the daemon thread is created the main thread goes to sleep for 5 seconds and then ends. Once the main-method thread ends there are no longer any user threads so the Java runtime shuts down the application, despite the fact there is a window being displayed.
| 1 |
import java.awt.*; |
| 2 |
|
| 3 |
public class Daemon_3 { |
| 4 |
public static void main(String[] args) { |
| 5 |
Thread t1 = new Thread() { |
| 6 |
public void run() { |
| 7 |
Frame f = new Frame(); |
| 8 |
f.setBounds(30, 30, 400, 400); |
| 9 |
f.setVisible(true); |
| 10 |
} |
| 11 |
}; // end of t1 |
| 12 |
|
| 13 |
t1.setDaemon(true); |
| 14 |
t1.start(); |
| 15 |
|
| 16 |
try { Thread.sleep(5000); } |
| 17 |
catch(InterruptedException e) {} |
| 18 |
} // main() |
| 19 |
} // Daemon_3 |
Don't Sell your Soul
The moral of this story is that daemon threads should be used judiciously. They were designed to be used as servants to their user thread masters. When no more user threads exist daemon threads lose their reason for living and the Java runtime steps in and mercifully ends their existence.
Because the life of a daemon thread can be a precarious one you should be very careful with the sort of tasks you assign to them. Since the Java runtime will kill daemon threads abruptly you should not assign them any critical task which may leave your system in an inconsistent state when the thread is shutdown.
At this point, you may be asking yourself, "So what good are these daemon threads?". In fact, their utility is extremely limited. The only advantage afforded by daemon threads is that you can "create them and forget them". Since daemon threads are automatically stopped when no user threads exist you do not need to provide any sort of signaling or polling mechanism to tell a daemon thread to stop running. Instead, you can rely on the Java runtime to stop them when all user threads end.
When deciding whether or not to use a daemon thread, continually ask yourself, "what if this daemon thread is stopped abruptly at this point in the code?". If you are sure there are no adverse repercussions, you may want to consider a daemon thread, although as a rule, I would recommend against using them.
Trackback(0)
|