Java - Thread Life Cycle

Hello there, aspiring Java programmers! Today, we're going to dive into one of the most exciting aspects of Java programming: the life cycle of threads. Don't worry if you're new to programming; I'll guide you through this journey step by step, just as I've done for countless students over my years of teaching. So, grab a cup of coffee (or tea, if that's your thing), and let's embark on this thrilling adventure together!

Java - Thread Life Cycle

What is a Thread?

Before we jump into the life cycle, let's start with the basics. Imagine you're in a busy kitchen. The chef is chopping vegetables, the sous chef is stirring a pot, and the pastry chef is decorating a cake. Each of these tasks is happening simultaneously, right? Well, in the world of programming, these tasks would be like threads!

A thread is the smallest unit of execution in a program. It's like a mini-program running within your main program, allowing different parts of your code to run concurrently.

The Life Cycle of a Thread

Now, let's talk about the life cycle of a thread. Just like how we humans go through different stages in life (baby, toddler, teenager, adult), threads also go through various states during their lifetime.

States of a Thread Life Cycle in Java

  1. New
  2. Runnable
  3. Running
  4. Blocked/Waiting
  5. Terminated

Let's break these down with some examples, shall we?

1. New State

When you create a thread, it's in the "New" state. It's like a baby that has just been born but hasn't started crawling yet.

Thread myThread = new Thread();

In this example, we've created a new thread called myThread, but it hasn't started running yet.

2. Runnable State

Once you call the start() method on your thread, it enters the "Runnable" state. It's ready to run, but it's waiting for the thread scheduler to pick it up and execute it.

myThread.start();

Now myThread is like a toddler, eager to explore but waiting for mom or dad to take them to the park.

3. Running State

When the thread scheduler selects the thread from the runnable pool, it enters the "Running" state. This is where the thread is actually executing its task.

public void run() {
    System.out.println("Thread is running!");
}

This is the content of your run() method, which defines what the thread will do when it's in the running state.

4. Blocked/Waiting State

Sometimes, a thread might need to wait for a resource or for another thread to complete its task. In this case, it enters the "Blocked" or "Waiting" state.

synchronized(object) {
    try {
        object.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

In this example, the thread is waiting for object to notify it before it can continue.

5. Terminated State

Finally, when a thread completes its task or if an uncaught exception occurs, it enters the "Terminated" state. It's like retirement for threads!

public void run() {
    System.out.println("Thread is running!");
    // Thread task completed
}

Once this run() method completes, the thread will terminate.

Flow Chart of Java Thread Life Cycle

To visualize this better, let's look at a flow chart:

[New] --> [Runnable] --> [Running] --> [Terminated]
            ^    |           |
            |    |           |
            |    v           v
            |  [Blocked/Waiting]
            |___________________|

Java Example for Demonstrating Thread States

Now, let's put it all together with a complete example:

public class ThreadLifeCycleDemo implements Runnable {
    public static Thread thread1;
    public static ThreadLifeCycleDemo obj;

    public static void main(String[] args) {
        obj = new ThreadLifeCycleDemo();
        thread1 = new Thread(obj);

        // Thread is in NEW state
        System.out.println("State of thread1 after creating it - " + thread1.getState());
        thread1.start();

        // Thread is in RUNNABLE state
        System.out.println("State of thread1 after calling .start() method on it - " + thread1.getState());
    }

    public void run() {
        thread myThread = new thread(new ThreadLifeCycleDemo());
        // Thread is in NEW state
        System.out.println("State of myThread after creating it - " + myThread.getState());
        myThread.start();

        // Thread is in RUNNABLE state
        System.out.println("State of myThread after calling .start() method on it - " + myThread.getState());

        try {
            // moving thread1 to timed waiting state
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("State of myThread after calling .sleep() method on it - " + myThread.getState());

        try {
            // waiting for myThread to die
            myThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("State of myThread when it has finished execution - " + myThread.getState());
    }
}

This example demonstrates all the states a thread goes through. When you run this program, you'll see output showing the different states of the threads as they progress through their life cycles.

Conclusion

And there you have it, folks! We've journeyed through the life cycle of a Java thread, from its birth in the "New" state to its final rest in the "Terminated" state. Remember, understanding thread states is crucial for writing efficient multithreaded applications.

Just like in life, threads go through various stages, each with its own characteristics and challenges. By mastering these concepts, you're one step closer to becoming a Java threading expert!

Keep practicing, keep coding, and most importantly, keep having fun with Java! Who knows, maybe one day you'll be teaching this to a new generation of programmers. Until next time, happy coding!

Credits: Image by storyset