Thread States

Author: Ter-Petrosyan Hakob

In Java, a thread can be in six different states at any moment:

Each state shows what a thread is doing or waiting for. You can check a thread’s current state using the getState() method.

When you create a thread using the new keyword, for example:

Thread myThread = new Thread(() -> System.out.println("Hello!"));

the thread does not start immediately. It is in the New state. This means it exists in memory, but the program has not yet started running any code inside it.

Think of it like planning a new trip: you have packed your bag and booked tickets, but you haven’t left your house yet. Before a thread can run, the system must perform some preparation work, such as allocating memory and setting up internal structures.

Thread backgroundTask = new Thread(() -> System.out.println("Processing data..."));
System.out.println(backgroundTask.getState()); // Output: NEW

At this point, the thread is created but not started, so its state is NEW. To start it, you would call:

backgroundTask.start();

Runnable Threads

After you call the start() method on a thread, it enters the Runnable state.

Being in the Runnable state does not mean the thread is running immediately. Instead, it means the thread is ready to run, and it is waiting for the CPU (processor) to give it time. Java does not treat “running” as a separate state—when a thread is actively running, it is still considered Runnable.

Think of it like waiting in line for a ride at an amusement park. You are ready and standing in line, but you can only ride when it’s your turn.

How Threads Share CPU Time

A running thread does not keep running forever. Threads take turns, allowing other threads to run. The way threads are scheduled depends on the operating system and the type of thread.

Starting from Java 21, there are two types of threads:

class MyTask extends Thread {
    public void run() {
        for (int i = 1; i <= 3; i++) {
            System.out.println(getName() + " is running: " + i);
            Thread.yield(); // Suggests to the scheduler to let another thread run
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        Thread t1 = new MyTask();
        Thread t2 = new MyTask();

        t1.start();
        t2.start();
    }
}

In this example:


Think of it like saying, “I’m ready to wait; maybe someone else can go first,” but the system might ignore you.

Blocked and Waiting

When a thread is blocked or waiting, it becomes inactive for a short time. It doesn’t run any code and uses very few resources. The thread scheduler decides when to make it active again. The exact process depends on why the thread became inactive.

In practice, the difference between the blocked and waiting states is not usually significant. We will often say that a thread is blocked when it is in the blocked, waiting, or timed waiting state. When a thread is blocked or waiting (or, of course, when it terminates), another thread will be scheduled to run.

When a thread is reactivated (for example, because its timeout has expired or it has succeeded in acquiring a lock), it becomes runnable and is eligible for being scheduled.

img2

Terminated Threads

A thread stops running (is terminated) for two reasons:

  1. It finishes normally when the run method ends.
  2. It stops suddenly when an uncaught exception ends the run method.