Java Thread Life Cycles
Tags: concurrency, java, threads, multithreading
Published: 2022-03-05 12:11:36

### Introduction

A thread is the smallest unit of processing. A thread can be in different states in a cycle leading from its creation to its termination.
This article explores the different states in the Java thread life cycle. This is the second article of a concurrency series. The first article introduced the concepts of Multi-threading, Concurrency, Asynchronous Programming and Parallel Programming. You might want to take a look [here](https://dev.to/ehizman/distinguishing-between-concurrency-parallelism-asynchronous-programming-and-multi-threading-3d4i).

### Definition of Terms

- **Process**: A process is an instance of a program that is currently being executed by the processor. Different instances of the same program can run on a computer as different processes. This means that when I run MS Word on my computer, for instance, it runs as a process. I can run different instances of MS Word on my computer. For each new instance of MS Word, the processor spins up a new process. Each process has its own unique stack, memory and data.
- **Thread**: A thread is a subset of a process. A process starts with one thread called the main thread. The main thread can branch into other threads. A process that contains only the main thread is called a **single-threaded process**. A process that contains more than one thread is called a **multi-threaded process**. All threads within a process all share the same code-segment, data-segment, registers, stack and program counter.

### Lifecycle of threads in Java

Java supports multithreading. A Java program can be designed in such a way that its different parts run on different threads. The execution of a Java program begins from the `main` method. The `main` method is executed on a special thread called the main thread, which is created by the [Java Virtual Machine](https://en.wikipedia.org/wiki/Java_virtual_machine)(JVM). Other threads are created as off-shoots of the main thread.

In Java, threads belong to the class- `java.lang.Thread`. You can create a Java thread by implementing the `Runnable` interface as shown in the following block:

```java
/*
 * CREATING A JAVA THREAD BY IMPLEMENTING THE RUNNABLE INTERFACE
*/

public class SimpleThreadTwo implements Runnable{

    //the run method contains code that the thread will execute
    @Override
    public void run() {
        System.out.println("A simple thread has been created by implementing the Runnable interface");
    }
}
```

You can also create a Java thread by extending the `Thread` class as shown in the following block:

```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
* CREATING A JAVA THREAD BY EXTENDING THE THREAD CLASS
* */


public class SimpleThread extends Thread {

    // the run method contains code that the thread will execute
    @Override
    public void run() {
        System.out.println("A simple thread has been created by extending the Thread class");
    }
}
```

To execute both threads defined above, you create an [ExecutorService](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html). The `ExecutorService` provides a thread pool that allows you to execute threads using the `execute` method as shown below:

```java
//creating an executor service that executes threads
class Executor{
    public static void main(String[] args) {
        SimpleThread simpleThread = new SimpleThread();
        SimpleThreadTwo simpleThreadTwo = new SimpleThreadTwo();

        // create the thread pool
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(simpleThread);
        executorService.execute(simpleThreadTwo);

        //the shutdown method notifies the executor service to stop accepting new tasks
        //but the executor service still continues to run tasks that have already been accepted
        executorService.shutdown();
    }
}
```

Output:
```bash
A simple thread has be created by extending the Thread class
A simple thread has been created by implementing the Runnable interface

Process finished with exit code 0
```

You can also execute threads using the `Thread` class by invoking the `start` method. **To execute a thread created by extending the `Thread` class**, you have to invoke the `start` method on the thread object as follows:

> Take note that you have to first create a class that extends java’s `Thread` class. (Using the `SimpleThread` class created above)

```java
public class MyThread {
    public static void main(String[] args) {
        SimpleThread simpleThread = new SimpleThread();
        simpleThread.start();
    }
}
```

Output:
```bash
A simple thread has be created by extending the Thread class

Process finished with exit code 0
```

**To execute a thread created by implementing the Runnable interface**, you have to pass in a `Runnable` as an argument to the `Thread` constructor. This is demonstrated in the code block below:

> Take note that you have to first create a class that implements java’s `Runnable` class before you can do this.
(Using the `SimpleThreadTwo` class created above.)

```java
public class MyThread {
    public static void main(String[] args) {
        SimpleThreadTwo simpleThreadTwo = new SimpleThreadTwo();
        
        //passing the Runnable object as an argument into the Thread class
        Thread thread = new Thread(simpleThreadTwo);
        thread.start();
    }
}
```

Output:
```bash
A simple thread has been created by implementing the Runnable interface

Process finished with exit code 0
```

It is important to highlight that creating a thread by implementing the `Runnable` interface is more encouraged than creating threads using the `Thread` class.

The `java.lang.Thread` class has a static enum property- `State`. The `State` property defines the potential state of a Java thread. During its life cycle, a java thread can belong to any of the following states:

- NEW
- RUNNABLE
- WAITING
- TIMED-WAITING
- BLOCKED
- TERMINATED

The following is a diagrammatic representation of the java thread lifecycle:

![Java Thread Life Cycle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2qfh394n2ljj93igb5s.jpg)
Source: [baeldung.com](https://www.baeldung.com/)

The following section describes these thread states in more detail:

- **NEW**: When a thread is created, it is in the **NEW** state. A thread remains in the new state until its `start` method is called.

```java
public class MyThread {
public static void main(String[] args) {
            SimpleThreadTwo simpleThreadTwo = new SimpleThreadTwo();
            //passing the Runnable object as an argument into the Thread constructor
            Thread thread = new Thread(simpleThreadTwo);
            System.out.printf("The current state of thread is %s", thread.getState());
    }
}
```

Output:
```bash
The current state of thread is NEW

Process finished with exit code 0
```

- **RUNNABLE**: A thread is in the **RUNNABLE** state when the processor executes its `start` method. Threads in the **RUNNABLE** state are either **READY** to run or are already **RUNNING**.

When a thread transitions to the **RUNNABLE** state, the thread starts first in the **READY** state. At the **READY** state, the thread has not been assigned processor time also called a **quantum or a time slice**. When a thread is assigned a time slice, **the thread is said to be dispatched**. A newly dispatched thread joins a queue of other dispatched threads that are also waiting to run. The operating system uses a [Thread Scheduler](https://www.javatpoint.com/thread-scheduler-in-java) to determine which thread to run.

When a thread starts to run, it transitions into its **RUNNING** state. In the **RUNNING** state, the task defined within the `run` method of the threads is executed.

```java
public class MyThread {
    public static void main(String[] args) {
            SimpleThreadTwo simpleThreadTwo = new SimpleThreadTwo();
            //passing the Runnable object as an argument into the Thread constructor
            Thread thread = new Thread(simpleThreadTwo);
            // the start method executes the code defined in the run method of the thread
        thread.start();
            System.out.printf("%nThe current state of thread is %s%n", thread.getState());
    }
}
```

- **WAITING**: A thread enters the **WAITING** state while it waits for another thread to perform a task. A running thread can be placed on wait when one of the following methods is invoked:
    - `wait`: The wait method causes an object to give up its timeslice and to release the monitor lock on a synchronized object. A monitor lock is a contract that gives a thread sole access to an object. The wait method causes the object to give up processor time and to transition from the **RUNNING** state to the **WAITING** state. A thread in waiting can transition back into execution when the thread that currently has the monitor lock calls the `notify` or `notifyAll` method.
    - `LockSupport.park`: The `LockSupport.park` method disables a thread unless a permit is available. A permit is a permission for a thread to continue execution. When the `park` method is called on the current thread, the thread remains in the **WAITING** state. When some other thread invokes the `unpark` method with the parked thread as the target, the parked thread goes back into the **RUNNING** state.
    - `join`: The `join` method allows a thread to remain in the **WAITING** state until another thread completes execution.

```java
public class WaitingStateDemo implements Runnable{
    public static Thread firstThread;

    public static void main(String[] args) {
            firstThread = new Thread(new WaitingStateDemo());
            firstThread.start();
    }
    @Override
    public void run() {
            Thread secondThread = new Thread(new WaitingStateDemoInner());
            secondThread.start();
         try {
                secondThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }


    static class WaitingStateDemoInner implements  Runnable{

            @Override
            public void run() {
                System.out.println("The current state of thread 2 is " + firstThread.getState());
        }
    }
}
```

Output:
```bash
The current state of thread 2 is WAITING

Process finished with exit code 0
```

Execution starts from the main method in the above program.
- First, we create `firstThread` and invoke its `run` method by calling `start`.
- In the `run` method of `firstThread`, we create `secondThread` and start it.
- While the processing of `firstThread` continues, we call the `join` method on `secondThread`. The `join` method puts `firstThread` in the **WAITING** state until `secondThread` has finished its execution.
- Since `firstThread` is waiting for `secondThread` to complete, you can get the state of `firstThread` from `secondThread`.

To better understand the **WAITING** state, consider this scenario:

You have an onsite interview for a position that has the prospects of an amazing salary. On your arrival for the interview, the secretary tells you to wait until the hiring manager notifies you to come in. At this point, you are in the **WAITING** state. You cannot proceed to the interview until the hiring manager notifies you to come in.

- **TIMED-WAITING**: A thread enters the **TIMED-WAITING** state when it is waiting for another thread to perform a task within a specified time interval. A thread can be put in the **TIMED-WAITING** state by calling one of the following methods:
    - thread.sleep(long millis)
    - thread.wait(int timeout) or thread.wait(int timeout, int nanos)
    - thread.join(long millis)
    - LockSupport.parkNanos
    - LockSupport.parkUntil

You can demonstrate the **TIMED-WAITING** state by creating a thread from the main thread. You can call the `sleep` method on the offshoot thread. This is shown as follows:

```java
public class TimedWaitingStateDemo {
    public static void main(String[] args) {
            Thread newThread = new Thread(new DemoThread());
         newThread.start();

        // the following sleep gives the ThreadScheduler enough time to start processing newThread
         try {
                Thread.sleep(1000);
             System.out.println("The current state of newThread is: " + newThread.getState());
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             System.err.println("Thread interrupted " + e);
         }
    }
}

class DemoThread implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("Thread interrupted " + e);
        }
    }
}
```

A thread in the **TIMED-WAITING** state transitions back to the **RUNNABLE **state when the task it is waiting for completes execution or when the specified time interval elapses. To better understand the **TIMED-WAITING** state, consider the following scenario:

You and a friend in another city get tickets to go see a music concert organized in your city. On the day of the concert, you agree with your friend to wait for him until 2 pm. If he does not arrive on/before 2 pm, you can go to the concert alone. Here, you are placed in the **TIMED-WAITING** state. You can choose to proceed with going to the concert after the specified time (until 2 pm) has elapsed.

- **BLOCKED**: A thread transitions into the **BLOCKED** state when one of the following happens during program execution:

    - When the thread is waiting for an I/O operation to complete.
    - When the thread is waiting to gain access to the monitor lock on a synchronized object. A monitor lock is a contract that gives a thread sole access to a synchronized object. A synchronized object is an object that is designed to be accessed by only one thread at a time.

To understand the **BLOCKED** state, consider this scenario:

You have a meeting with a friend but as you step out of your house, it begins to rain. At this point, you are in a **BLOCKED** state. You are blocked from meeting with your friend until the rain stops.

- **TERMINATED**: A thread enters the **TERMINATED** state ( sometimes called the **DEAD state**) when one of the following happens:
    - when it completely executes its task ( as defined in the run method).
    - when it terminates due to an error.

```java
public class TerminatedStateDemo implements Runnable{
    @Override
    public void run() {
            System.out.println("This demo is to show the terminated state");
}

    public static void main(String[] args) throws InterruptedException {
         Thread newThread = new Thread(new TerminatedStateDemo());
         newThread.start();
        // this sleep is intended to enable newThread execute completely
         Thread.sleep(5000);
         System.out.println("The current state of the new thread is : " + newThread.getState());
    }
}
```

Output:
```bash
This demo is to show the terminated state
The current state of the new thread is: TERMINATED

Process finished with exit code 0
```

### Thread Priorities and Thread Scheduling

The number of services assigned to a given thread is referred to as its priority. Every Java thread has a thread priority. The order in which threads are scheduled is determined by each thread’s thread-priority. Threads with a higher thread-priority are executed before threads with a lower thread priority. In Java, thread-priorities are scaled on a scale of 1 to 10.

- 1 is the lowest priority.
- 5 is the standard priority.
- 10 is the highest priority.

The priority of the main thread is set to 5 by default. Thread priority is a transferred property. Since every java thread is created off the main thread, every thread starts with a priority of 5. The priority of a thread can be programmed using the `setPriority` method. The following enums represent thread priorities:

- `Thread.MIN_PRIORITY` represents the lowest priority.
- `Thread.NORM_PRIORITY` represents the standard priority.
- `Thread.MAX_PRIORITY` represents the highest priority.

Below is a program to understand the Thread-Priority:

```java
public class ThreadPriority implements Runnable{
    @Override
    public void run() {
        System.out.println("The thread priority of the running thread is " + Thread.currentThread().getPriority());
    }

    public static void main(String[] args) {
        Thread firstThread = new Thread(new ThreadPriority());
        Thread secondThread = new Thread(new ThreadPriority());

        firstThread.setPriority(Thread.NORM_PRIORITY);
        secondThread.setPriority(Thread.MAX_PRIORITY);

        firstThread.start();
        secondThread.start();
    }
}
```

Output:

```bash
The thread priority of the running thread is 5
The thread priority of the running thread is 10

Process finished with exit code 0
```

> It is important to note that thread priorities alone do not guarantee the order in which threads execute.

An Operating System’s Thread Scheduler determines the order with which threads run. A simple implementation of the Thread Scheduler ensures that threads with the same level of priority are assigned processor resources in a round-robin fashion. However, Thread Schedulers are not that simple. Concurrency is a complex concept and the JVM provides utilities that abstract these complexities from the programmer.

### Starvation and DeadLock

Thread priorities determine the order in which threads are executed. Depending on the Operating System, a steady influx of higher priority threads could cause lower priority threads to stay in the waiting state indefinitely. Such indefinite postponement of thread execution is called starvation.
Closely, related to starvation is the concept of DeadLock. To explain Deadlock, let us say that there are two threads- Thread 1 and Thread 2. Thread 1 cannot execute because it is waiting (directly or indirectly) for Thread 2 to execute. Simultaneously, Thread 2 cannot execute because it is waiting for Thread 1 to execute. Both Thread 1 and Thread 2 are blocking each other, hence the term deadlock. The concept of deadlock concurrency is analogous to a traffic jam.

### Conclusion

In this article, you learnt about the different states of Java threads, from time of creation to termination.
I hope that you enjoyed the article and learnt something new too. You can follow me on Twitter on [@ehizman]()https://twitter.com/ehizman_tutorEd. This will help me write more valuable content.

Special shout-outs to [Confidence Okere](https://twitter.com/nomso_okere), [Oladimeji Omotosho](https://github.com/toshmanuel), and [Ozi Okoroafor](https://twitter.com/Ozifirebrand) for helping me with reviews and edits.

I look forward to hearing from you. Always code with ❤️