Skip to main content

6.1 Thread Creation, Execution & 6 Lifecycle States

← Back to Chapter 6: Multithreading & Concurrency

A thread is the smallest schedulable execution path managed by the operating system kernel.


1. Process vs Thread​

  • Process: An isolated execution environment with dedicated address space, file handles, and security context. eg : Spring Boot application or microservice
  • Thread: A lightweight execution path inside a process. All threads in a JVM share the same Java Heap Memory, but each thread maintains its own private Thread Stack and Program Counter (PC) Register. eg : HTTP Request, APIs

2. Ways to Define and Launch Threads​

2.1. Approach 1: Extending Thread class​

// Extending thread
class MyThread extends Thread {

@Override
public void run() {
// run() contains the task executed by this thread.
// We override it because Thread invokes this method when start() is called.
System.out.println("Running in: " + Thread.currentThread().getName());
}
}

2.2. Approach 2: Implementing Runnable (Preferred over extending Thread)​

// Implementing Runnable
Runnable task = () -> System.out.println("Running on: " + Thread.currentThread().getName());
Thread t1 = new Thread(task, "Worker-1");
t1.start(); // Spawns an underlying OS thread (never invoke run() directly!)

This approach is preferred over extending Thread class because :

  1. We cannot extend our class with other classes. As java does not support multiple inheritance
  2. Allows us to use the benefits of other classes if the task requires composition
  3. It allows us to write Lambda Expressions because Runnable is a Functional Interface

2.3 Approach 3: Callable<V> with Future<V> (Returns a value, throws checked exceptions)​

// Callable<V> with Future<V
Callable<Integer> calcTask = () -> {
Thread.sleep(100);
return 42;
};

3. Daemon vs User Threads​

  • Daemon Threads: Background threads that run in the background. eg : Garbage Collector, Logging thread
  • User Threads: Main threads that run in the foreground. eg : HTTP Request, APIs

4. Runnable, Callable, & Future​

Runnable -​

  1. Runnable is an interface used to represent a task that can be executed by a thread.
  2. Executes a task.
  3. Does not return a result.
  4. Cannot directly throw checked exceptions from run().
  5. Used with Thread or ExecutorService.

Callable -​

  1. Callable is an interface used to represent a task that returns a result after execution.
  2. Executes a task.
  3. Returns a result.
  4. Can throw checked exceptions.
  5. Generally submitted to an ExecutorService.

Future -​

  1. Future represents the result of an asynchronous computation.
  2. It is not the task itself. It is an object through which you can :
    • Get the result using get()
    • Check whether execution is complete using isDone()
    • Cancel the task using cancel()

Problem with Future -​

it is limited in handling asynchronous operations.

  1. get() is blocking
  2. Difficult to chain multiple operations
  3. Limited exception handling

CompletableFuture was introduced to make asynchronous programming more flexible and composable. It allows you to build non-blocking asynchronous pipelines.

Runnable → "Do this task"
Callable → "Do this task and give me a result"
Future → "I'll give you the result/status of that task later"

5. The 6 JVM Thread Lifecycle States (Thread.State)​

┌─────────────────────┐
│ NEW │
│ │
│ Thread object │
│ created, but │
│ not started │
└──────────┬──────────┘
│
start()
│
▼
┌────────────────────────────┐
│ RUNNABLE │
│ │
│ Ready to run / Running │
│ │
│ JVM scheduler decides │
│ when CPU is given │
└───────┬──────┬───────┬─────┘
│ │ │
lock busy │ │ │
┌─────────┘ │ └──────────────┐
▼ │ │
┌─────────────────┐ │ │
│ BLOCKED │ │ │
│ │ │ │
│ Waiting to │ │ │
│ acquire a │ │ │
│ synchronized │ │ │
│ monitor lock │ │ │
└────────┬────────┘ │ │
│ │ │
lock acquired │ │
│ │ │
└───────────────►│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ WAITING │ │ TIMED WAITING │
│ │ │ │
│ Waiting │ │ Waiting for a │
│ indefinitely │ │ specific amount │
│ for another │ │ of time │
│ thread │ │ │
└────────┬────────┘ └──────────┬──────────┘
│ │
notification / time expires /
interrupt / signal interrupt
│ │
└───────────┬────────────┘
│
▼
RUNNABLE
│
│
run() completes
│
▼
┌──────────────────┐
│ TERMINATED │
│ │
│ Thread execution │
│ has finished │
└──────────────────┘
  1. NEW: Created via new Thread(), but start() has not been invoked.
  2. RUNNABLE: Ready for CPU scheduling or actively executing bytecode in the JVM.
  3. BLOCKED: Waiting to acquire an intrinsic monitor lock (synchronized) currently held by another thread.
  4. WAITING: Indefinitely waiting for another thread to perform an action (Object.wait(), Thread.join(), LockSupport.park()).
  5. TIMED_WAITING: Waiting with a specified timeout (Thread.sleep(ms), Object.wait(timeout)).
  6. TERMINATED: Execution of run() completed normally or threw an uncaught exception.