|
|
< Day Day Up > |
|
2.3 The Lifecycle of a ThreadIn our example, we gloss over some of the details of how the thread is actually started. We'll discuss that in more depth now and also give details on other lifecycle events of a thread. The lifecycle itself is shown in Figure 2-4. The methods of the Thread class that affect the thread's lifecycle are: package java.lang;
public class Thread implements Runnable {
public void start( );
public void run( );
public void stop( ); // Deprecated, do not use
public void resume( ); // Deprecated, do not use
public void suspend( ); // Deprecated, do not use
public static void sleep(long millis);
public static void sleep(long millis, int nanos);
public boolean isAlive( );
public void interrupt( );
public boolean isInterrupted( );
public static boolean interrupted( );
public void join( ) throws InterruptedException;
}Figure 2-4. Lifecycle of a thread![]() 2.3.1 Creating a ThreadThe first phase in this lifecycle is thread creation. Threads are represented by instances of the Thread class, so creating a thread is done by calling a constructor of that class. In our example, we use the simplest constructor available to us. Additional constructors of the Thread class allow you to specify the thread's name or a Runnable object to serve as the thread's target. All threads have names that serve to identify them in the virtual machine. By default, that name consists of information about the thread: its priority, its thread group, and other thread information we discuss in later chapters. If you like, you can give a thread a different name, perhaps one that will have meaning to you if you print it out. We discuss the Runnable interface later in this chapter. 2.3.2 Starting a ThreadA thread exists once it has been constructed, but at that point it is not executing any code. The thread is in a waiting state. In this waiting state, other threads can interact with the existing thread object. Various attributes of the waiting thread can be set: its priority, its name, its daemon status, and so on. We'll see examples of these throughout the book, but each of these attributes is set simply by calling a method on the waiting thread. Therefore, even though the thread is waiting, its state may be changed by other threads. When you're ready for the thread to begin executing code, you call its start() method. This method performs some internal housekeeping and calls the thread's run() method. When the start() method returns, two threads are now executing in parallel: the original thread (which has returned from calling the start() method) and the newly started thread (which is now executing its run() method). After its start() method has been called, the new thread is said to be alive. In fact, the Thread class has an isAlive() method that tells you the state of the thread: if the isAlive() method returns true, the thread has been started and is executing its run() method. If the isAlive( ) method returns false, however, the thread may not be started yet or may be terminated. 2.3.3 Terminating a ThreadOnce started, a thread executes only one method: the run() method. The run() method may be very complicated, it may execute forever, and it may call millions of other methods. Regardless, once the run() method finishes executing, the thread has completed its execution. Like all Java methods, the run() method finishes when it executes a return statement, when it executes the last statement in its method body, or when it throws an exception (or fails to catch an exception thrown to it). As a result, the only way to terminate a thread is to arrange for its run() method to complete. If you look at the documentation of the Thread class, you notice that the class contains a stop() method which seems like it might be used to terminate a thread. It turns out that the stop() method has an inherent problem (an internal race condition, see Chapter 3). As a result, the stop() method is deprecated and should not be used. Some Java implementations prohibit its use directly, and the security manager can also be used to prohibit programs from calling it. There are many threads that you don't need to stop. Often, threads are performing a fixed task, and you always want the task to run to completion. In other cases, such as our example, the thread can run until the application exits (e.g., when we call the System.exit() method in response to the user pressing the Quit button). Often, however, you want a thread to continue to execute until some other condition is met. In our typing game, we might want one RandomCharacterGenerator thread to terminate so that we can start a different one (perhaps one with a different set of characters available to it). We explore some basic ways to arrange for a thread to stop later in this chapter. The run() method cannot throw a checked exception, but like all Java methods, it can throw an unchecked exception. Throwing an unchecked exception (an exception that extends the RuntimeException class)梠r failing to catch a runtime exception thrown by something the run( ) method has called梐lso causes a thread to stop. Threads can arrange for special exception processing in their termination; for details, see Chapter 13. 2.3.4 Pausing, Suspending, and Resuming ThreadsOnce a thread begins executing its run() method, it continues execution until the run() method completes. If you're familiar with other thread models, you may know of a concept called thread suspension, where a thread is told to pause its execution. Later, the thread is resumed, which is to say that it is told to continue its execution. The Thread class contains suspend() and resume() methods, but they suffer from the same race condition problem as the stop() method, and they, too, are deprecated. It is possible for a thread to suspend its own execution for a specific period of time by calling the sleep() method. We use that method in our RandomCharacterGenerator thread. When a thread executes the sleep() method, it pauses for a given number of milliseconds (or milliseconds plus nanoseconds), during which it is said to be asleep. When the pause time has elapsed, the thread wakes up and continues execution with the statements immediately following the sleep() method. Strictly speaking, sleeping is not the same thing as thread suspension. One important difference is that with true thread suspension, one thread would suspend (and later resume) another thread. Conversely, the sleep() method affects only the thread that executes it; it's not possible to tell another thread to go to sleep. Threads can use the wait and notify mechanism discussed in Chapter 4 to achieve the functionality of thread suspension and resumption. The difference is that the threads must be coded to use that technique (rather than a generic suspend/resume mechanism that could be imposed from other threads). 2.3.5 Thread CleanupA thread that has completed its run() method has terminated. It is no longer active (the isAlive() method returns false). However, the thread object itself may be holding interesting information. As long as some other active object holds a reference to the terminated thread object, other threads can execute methods on the terminated thread and retrieve that information. If the thread object representing the terminated thread goes out of scope, the thread object is garbage collected. On some platforms, this also has the effect of cleaning up system resources associated with the thread. In general, then, you should not hold onto thread references so that they may be collected when the thread terminates. One reason to hold onto a thread reference is to determine when it has completed its work. That can be accomplished with the join() method. The join() method is often used when you have started threads to perform discrete tasks and want to know when the tasks have completed. You'll see that technique in use in the examples in Chapter 15. The join() method blocks until the thread has completed its run() method. If the thread has already completed its run() method, the join() method returns immediately. This means that you may call the join() method any number of times to see whether a thread has terminated. Be aware, though, that the first time you call the join() method, it blocks until the thread has actually completed. You cannot use the join() method to poll a thread to see if it's running (instead, use the isAlive() method just discussed). |
|
|
< Day Day Up > |
|