Fundamentals 10 min read

Mastering Java Thread Lifecycle: From NEW to TERMINATED Explained

This article provides a comprehensive guide to Java's thread lifecycle, detailing each of the six thread states, their meanings, how they are triggered, and practical code examples that demonstrate state transitions and logging output.

FunTester
FunTester
FunTester
Mastering Java Thread Lifecycle: From NEW to TERMINATED Explained

Java Thread States

Java defines six distinct thread states that a Thread instance can occupy during its lifetime:

NEW – The thread has been created but not yet started.

RUNNABLE – The thread is ready to run or is currently executing.

BLOCKED – The thread is waiting to acquire a monitor lock.

WAITING – The thread is waiting indefinitely for another thread to perform a specific action.

TIMED_WAITING – The thread is waiting for a specified period before proceeding.

TERMINATED – The thread has completed execution.

The following diagram visualizes these states and their possible transitions:

Thread lifecycle diagram
Thread lifecycle diagram

Enum Definition in JDK

public enum State {
    /** Thread state for a thread which has not yet started. */
    NEW,
    /** Thread state for a runnable thread. */
    RUNNABLE,
    /** Thread state for a thread blocked waiting for a monitor lock. */
    BLOCKED,
    /** Thread state for a waiting thread. */
    WAITING,
    /** Thread state for a waiting thread with a timeout. */
    TIMED_WAITING,
    /** Thread state for a terminated thread. */
    TERMINATED;
}

NEW State

A thread in the NEW state has been instantiated but not started.

public class NewThread implements Runnable {
    public static void main(String[] args) {
        Runnable runnable = new NewThread();
        Thread t = new Thread(runnable);
        log.info(t.getState().toString()); // prints NEW
    }
    @Override
    public void run() {}
}

RUNNABLE State

When a thread is ready to execute or is currently executing, it is in the RUNNABLE state.

public class RunnableThread implements Runnable {
    @Override
    public void run() {}
    public static void main(String[] args) {
        Runnable runnable = new RunnableThread();
        Thread t = new Thread(runnable);
        t.start();
        log.info(t.getState().toString()); // prints RUNNABLE
    }
}

BLOCKED State

A thread enters BLOCKED when it attempts to acquire a monitor lock that another thread holds.

public class BlockThread implements Runnable {
    @Override
    public void run() { loopResource(); }
    public static synchronized void loopResource() {
        while (true) { /* infinite loop */ }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new BlockThread());
        Thread t2 = new Thread(new BlockThread());
        t1.start();
        t2.start();
        Thread.sleep(1000);
        log.info(t1.getState().toString()); // RUNNABLE
        log.info(t2.getState().toString()); // BLOCKED
        System.exit(0);
    }
}

WAITING State

A thread is in WAITING when it calls one of the following without a timeout: Object.wait(), Thread.join(), or LockSupport.park().

public class WaitThread implements Runnable {
    public static Thread t1;
    @Override
    public void run() {
        Thread t2 = new Thread(() -> {
            try { Thread.sleep(10000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
            log.info("t1" + t1.getState().toString());
        });
        t2.start();
        try { t2.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        log.info("t2" + t2.getState().toString());
    }
    public static void main(String[] args) {
        t1 = new Thread(new WaitThread());
        t1.start();
    }
}

TIMED_WAITING State

The TIMED_WAITING state occurs when a thread waits for a specified period, such as via Thread.sleep(long), Object.wait(long), Thread.join(long), LockSupport.parkNanos, or LockSupport.parkUntil.

public class TimedWaitThread implements Runnable {
    @Override
    public void run() {
        try { Thread.sleep(5000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }
    public static void main(String[] args) throws InterruptedException {
        TimedWaitThread obj = new TimedWaitThread();
        Thread t = new Thread(obj);
        t.start();
        Thread.sleep(1000);
        log.info(t.getState().toString()); // prints TIMED_WAITING
    }
}

TERMINATED State

A thread reaches TERMINATED after its run() method finishes.

public class TerminatedThread implements Runnable {
    @Override
    public void run() {}
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new TerminatedThread());
        t.start();
        Thread.sleep(1000);
        log.info(t.getState().toString()); // prints TERMINATED
    }
}

Understanding these states helps developers diagnose concurrency issues, design proper synchronization, and write more predictable multithreaded Java applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyThreadLifecyclemultithreading
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.