Saturday, March 19, 2011

Introduction to Thread in Java (part 2): Thread Life Cycle

Welcome to the second installment of the series "Introduction to Thread in Java." If you haven't read part 1, here is the link for you. Please read it because we covered a lot of important and fundamental concepts in the first part.

In this section, we'll learn more about the life cycle of threads. Specifically, we need to learn what states threads go through and why / how they end up in a particular state.

Overview

In the simplest form, a thread's life cycle consists of five states:

  1. New state: this is when the threadable / Thread object is first created by calling the constructor of the Thread class. For example, our thread is in new state after this statement Thread newThread = new (runnableObj, threadName);
  2. Runnable / Read-to-run state: after calling the start() method on the thread, it enters the runnable state. That means it is ready to run or to go to some other states. As of the current version of Java, a thread must enter the runnable state before going to any other state.
  3. Running state: a thread is in this state while its run() method is executing. During this state, the thread can go to blocked state if it gets blocked or has to wait for other threads. When the run() method finishes, this state ends.
  4. Blocked/waiting state: while running a thread can be put to sleep, interrupted or blocked by other threads. There are many reasons why this may happen. We'll go deeper in the next section.

  5. Terminated / dead state: when a thread reaches this state, its life ends. It can never be revived again. Normally, a thread enters this state because its run() method has ended. However, a thread can also be terminated even before it is in the runnable state or during the waiting state by calling stop() or suspense() on the thread. I don't suggest using any of those methods to move a thread to its terminated state because those methods have been deprecated by Java and are not thread safe. Therefore, ending the run() method is the best way to go. We'll discuss more on how to do that later.

Here is the UML state diagram that describes the states that a Java thread goes through and how it gets to those states.

Next, let's examine the Blocked/Waiting state and the Terminated/Dead state. They are more complicated than other three states.

Blocked / Waiting state

As we have seen, a thread can only enter this state while it is running. So why does a thread enter this state? There are many causes. The main three are:

  1. Yielding for another thread: current thread yields for another thread to run first. Sometimes, we have a particular thread that needs to run immediately, so we call the yield() method on any running thread to reclaim CPU and resources for the important thread. As the result, any running thread enters the blocked state until the important thread finishes and releases the CPU / resources.
  2. Waiting for another thread: somewhat similar to yielding, there are times when a thread needs to wait for another thread to finish first before it can continue. For instance, if two threads share the same resource, and one of the two is holding that resource, then the other thread needs to wait for that resource to be released.
  3. Waiting for I/O: as you may know, the I/O speed is extremely slow compared to the CPU speed. Thus, if a thread needs some resources / inputs from I/O, it may need to enter the waiting state in order to let the CPU work on other threads. This practice is better for utilizing the CPU because it should be working on other threads / processes instead of siting idle and waiting for a particular thread.

The Java Thread API provides all functions needed to resolve all the situations above. For example, the join() method allows one thread to wait for the completion of another thread. Moreover, you can always cause a thread to enter the waiting state at anytime by calling the method interrupt() on that thread (there are some cases where threads are not interruptable however). Here is the link to the Java Thread API for further reading.

Terminated / Dead State

Once a thread enters this state, it cannot come back to other states. There two distinct ways to terminate the thread, letting the run() method return and calling stop(), suspense() or destroy() method on the running thread. The former is recommended because it ensures thread safe. In fact, Java has already deprecated stop(), suspense() and destroy() method in the new API.

Here is an excellent article that points out why those methods are bad and why stopping a thread through run() is a good practice.

That's all for the second part of this series. Please leave any comment or suggestion because they are always helpful and appreciated :)

1 comment:

  1. Interesting guide - helped me with my programming class via Aventa. Thanks.

    ReplyDelete