By WebNest Studio Engineering Team
Java - Core Tutorial
Multithreading Basics and Thread Life Cycle
A process is an independently running program with its own memory space — for example, your browser and your IDE are two separate processes, and one cannot directly read the other's memory. A thread is a lightweight sub-unit of a process; multiple threads within the same process share that process's memory (heap, static fields) but each thread keeps its own stack, program counter, and local variables. Multithreading is the ability to run several threads concurrently within a single process.
Java has supported multithreading since its first release through the java.lang.Thread class and the Runnable interface. Threads are useful because they let a program do more than one thing "at the same time" — for example, a server handling many client connections, or a UI staying responsive while a background task loads data — without needing multiple separate processes, which would be far more expensive to create and communicate between.
Why it matters
Any server handling many requests, or any application that stays responsive while it works, uses threads. Before you can reason about what a thread is doing — or why it appears stuck — you need the vocabulary of its states. A thread dump from a hung production system is simply a list of threads and the state each one is in.
Why Threads Instead of Processes
Creating a new process means the operating system allocates a fresh memory space and duplicates resources, which is comparatively slow and memory-heavy. Creating a new thread is much cheaper because it reuses the same process memory and just adds a new stack and execution path. Threads within one process can also communicate directly through shared variables, whereas processes typically need explicit inter-process communication (sockets, pipes, files) to exchange data.
The Thread Life Cycle
Every Java thread moves through a well-defined set of states, represented by the enum Thread.State. Understanding these states is essential for debugging concurrency issues, because tools like thread dumps report exactly these state names.
- New — the thread object has been created (
new Thread(...)) butstart()has not yet been called; no OS-level thread exists yet. - Runnable — after
start()is called, the thread is eligible to run; it may be actively executing on a CPU core or simply waiting its turn from the thread scheduler. Java does not distinguish "ready" from "running" as a separate state — both fall under RUNNABLE. - Blocked — the thread is waiting to acquire an intrinsic lock (a
synchronizedblock or method) that another thread currently holds. - Waiting — the thread is waiting indefinitely for another thread to perform a specific action, typically via
Object.wait()(with no timeout),Thread.join()(with no timeout), orLockSupport.park(). - Timed Waiting — like Waiting, but bounded by a timeout, as with
Thread.sleep(ms),wait(ms), orjoin(ms). - Terminated — the thread has finished executing its
run()method, either normally or due to an uncaught exception. A terminated thread cannot be restarted.
Who Controls the Transitions
Moving from New to Runnable is always your explicit action — calling start(). Moving out of Runnable into Blocked, Waiting, or Timed Waiting happens automatically based on what the thread's code does (trying to enter a locked block, calling wait(), calling sleep()). The JVM thread scheduler — not your program — decides exactly when a Runnable thread actually gets CPU time, and that decision is not guaranteed to be fair or deterministic across runs.
Example
Observing thread states at different points in the life cycle
public class LifeCycleDemo {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
});
System.out.println("Before start(): " + worker.getState()); // NEW
worker.start();
System.out.println("Just after start(): " + worker.getState()); // RUNNABLE
Thread.sleep(50); // give the worker time to reach sleep()
System.out.println("While worker sleeps: " + worker.getState()); // TIMED_WAITING
worker.join();
System.out.println("After join(): " + worker.getState()); // TERMINATED
}
}
Before start(): NEW
Just after start(): RUNNABLE
While worker sleeps: TIMED_WAITING
After join(): TERMINATED
Common Mistakes
- Assuming RUNNABLE means "currently executing on a CPU" — it only means "eligible to run"; the scheduler decides the rest.
- Calling start() twice on the same Thread object — this throws IllegalThreadStateException, because a terminated or already-started thread cannot restart.
- Confusing a "process" with a "thread" and assuming threads have completely separate memory, when in fact they share the heap and static state of their process.
Exercise
Print the state of a thread at two moments: after it has been created but not started, and after it has finished. Use join() to wait for it to finish.
Expected output: NEW then TERMINATED
public class ThreadStates {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> { });
// TODO: print the state before starting the thread
// TODO: start it, wait for it to finish, then print the state again
}
}
Show hints
worker.getState()returns one of theThread.Statevalues.worker.join()makes the main thread wait until the worker has finished.
Show solution
public class ThreadStates {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> { });
System.out.println(worker.getState()); // NEW
worker.start();
worker.join();
System.out.println(worker.getState()); // TERMINATED
}
}
Quick quiz
1. What state is a thread in after new Thread(task) but before start() is called?
- A. NEW
- B. RUNNABLE
- C. WAITING
- D. BLOCKED
Show answer
A. A thread object that has been created but not started is in the NEW state.
2. Which state does a thread enter when it calls Thread.sleep(1000)?
- A. BLOCKED
- B. TIMED_WAITING
- C. WAITING
- D. TERMINATED
Show answer
B. Waiting with a time limit, as with sleep or a timed wait, is the TIMED_WAITING state.
3. Can a thread that has reached TERMINATED be started again?
- A. Yes, by calling start() again
- B. Only if it is a daemon thread
- C. No; calling start() again throws IllegalThreadStateException
- D. Only after calling join()
Show answer
C. A thread can be started exactly once. To run the task again, create a new Thread.
Interview questions
What is the difference between a process and a thread?
Show answer
A process is a running program with its own memory space; processes are isolated from each other. A thread is a path of execution inside a process. All threads of a process share its heap memory, while each has its own call stack. Threads are cheaper to create and switch between, but sharing memory means they must coordinate access to shared data.
What are the states of a Java thread?
Show answer
There are six, defined in Thread.State. NEW: created but not started. RUNNABLE: running or ready to run. BLOCKED: waiting to acquire a lock. WAITING: waiting indefinitely for another thread, after wait() or join(). TIMED_WAITING: waiting for a limited time, after sleep() or a timed wait. TERMINATED: finished.
Key Points to Remember
- A process has isolated memory; threads within a process share memory but have their own stack.
- Thread.State values: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
- start() moves a thread from NEW to RUNNABLE; the actual CPU scheduling is controlled by the JVM/OS, not your code.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering