HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Have you ever wondered why it's necessary to call System.exit() to force your Java UI application to exit? Have a look at the code in Listing 1.

After the setVisible() method has been called at line 15, the main() method completes execution. Why doesn't the program end at that point?

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), the Java runtime promptly closes down the application. On the other hand, if at least one user thread is alive, the Java runtime won't terminate your application. In all other respect(s) the Java runtime treats daemon threads and user threads in exactly the same manner.

When your main() method initially receives control from the Java runtime, it executes in the context of a user thread. As long as the main-method thread or any other user thread remains alive, your 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();

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 doesn't call setDaemon() on the new thread before it's started, the new thread will inherit the "daemon-status" of the creating thread. For example, unless setDaemon(false) is called, all threads created by daemon threads will also be daemon threads; likewise, unless setDeamon(true) is called, all threads created by user threads will be user threads.

The program in Listing 2 illustrates this behavior. The program creates a thread, t1, whose only purpose in life is to create another thread, t2, whose destiny is to print a greeting, "Pleased to meet you," for all eternity. If you run this code you'll see that even though the main thread ends, t2 goes on forever, printing its tempting message. This behavior is due to the fact that t2 inherited its user thread status from its creator, t1. t1 in turn inherited its user thread status from its creator, the main-method thread, which, as I said, is always created by the Java runtime as a user thread.

By uncommenting line 18, t1 becomes designated as a daemon. When t1 creates t2, it too becomes a daemon thread. As a result, when the main-method thread exits, the Java runtime will end the application, since the only remaining thread (t2) is a daemon. This may or may not be the functionality you wanted or expected.

Exorcise the Daemons
Applying what we've learned about daemon threads, let's consider again why it's usually necessary for a Java graphical application to call System.exit() in order to end. As it turns out, the first time an application makes a user-interface component (e.g., Frame) visible, Java's internal AWT plumbing creates several threads behind the scenes. These threads are responsible for handling event queue management and window repainting. Typically, the first UI component made visible is a Frame or Dialog (or one of their JFC derivatives) via a call to setVisible(true). If the call to setVisible() is made from within a user thread (such as the main-method thread), these new AWT threads will also be user threads and won't be shut down simply because the main-method thread ends. This explains why your user interface is visible even after the main-method thread ends.

Let's put what we've learned to the test. The program in Listing 3 creates a Frame from within a daemon thread. After the daemon thread is created, the main thread goes to sleep for five 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.

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 benign existence.

Because the life of a daemon thread can be a precarious one, you should be careful with the sort of tasks you assign to them. A somewhat contrived yet illustrative example of their perils is a daemon thread dedicated to opening a log file, appending to it, then closing the log file at a predetermined interval. When the Java runtime determines that all user threads have ended, it will quickly kill the daemon logging thread, possibly resulting in an inconsistent log file. To avoid this it's best to structure your code so that any work assigned to a daemon thread will be completed before all the user threads die. So don't give in to temptation - be careful using daemon threads...and behave yourself.

Author Bio
Tony LaPaso is a Java application specialist and a Sun-certified Java programmer working for Greenbrier & Russel, Inc. (www.gr.com), in Phoenix, Arizona. His particular area of interest is distributed application development using RMI, EJBs, servlets and JSPs. Tony holds a master's degree in computer science from Arizona State University.
Tony can be contacted at: [email protected]

	

Listing 1:

 1: import java.awt.*;
 2: import java.awt.event.*;
 3:
 4: public class Tester {
 5:    public static void     
       main(String[] args) {
 6:       Frame f = new Frame();
 7:
 8:       f.addWindowListener(new 
          WindowAdapter() {
 9:          public void windowClos-
             ing(WindowEvent evt) {
10:             System.exit(0);
11:          }
12:       });
13:
14:       f.setBounds(30, 30, 400, 
          400);
15:       f.setVisible(true);
16:    }
17: }



Listing 2:

 1: public class Tester {
 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:          }
15:       }; // 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: } // Tester


Listing 3:

 1: import java.awt.*;
 2:
 3: public class Tester {
 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: } // Tester




 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.