Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Concurrency & Multithreading

Threads & Runnable

  • Introduction to Threads
  • ExecutorService & Thread Pools

Synchronization & Memory Model

  • synchronized and Locks
  • volatile and the Memory Model
  • CompletableFuture

Concurrent Collections

  • ConcurrentHashMap & CopyOnWriteArrayList
Chaturmind
← Java Concurrency & Multithreading

Threads & Runnable

  • Introduction to Threads
  • ExecutorService & Thread Pools

Synchronization & Memory Model

  • synchronized and Locks
  • volatile and the Memory Model
  • CompletableFuture

Concurrent Collections

  • ConcurrentHashMap & CopyOnWriteArrayList
HomeLearnJavaJava ConcurrencyThreads and Concurrency
✓ FreeIntermediate· 12 min read

Introduction to Threads

Create and manage threads with Thread, Runnable, and understand the thread lifecycle.

Published February 10, 2025


Introduction to Java Threads

A thread is the smallest unit of execution within a process. Java supports multithreading natively, allowing multiple threads to run concurrently within the same JVM process, sharing heap memory.

Creating Threads

Option 1: Extend Thread

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Running in: " + Thread.currentThread().getName());
    }
}

new MyThread().start(); // start() creates a new OS thread and calls run()

Option 2: Implement Runnable (preferred)

Runnable task = () -> System.out.println("Task in: " + Thread.currentThread().getName());

Thread t = new Thread(task, "worker-1");
t.start();

Prefer Runnable over extending Thread — it separates the task from the thread mechanism, and a class can only extend one class.

Thread Lifecycle

NEW → RUNNABLE → [RUNNING] → TERMINATED
              ↕
         BLOCKED/WAITING/TIMED_WAITING
  • NEW: Thread created but not started
  • RUNNABLE: Ready to run or running (JVM scheduler decides)
  • BLOCKED: Waiting for a monitor lock (e.g., synchronized)
  • WAITING: Waiting indefinitely (Object.wait(), Thread.join())
  • TIMED_WAITING: Waiting with timeout (Thread.sleep(ms), LockSupport.parkNanos())
  • TERMINATED: run() completed or threw an exception
Thread t = new Thread(() -> { /* ... */ });
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE
t.join();                          // wait for completion
System.out.println(t.getState()); // TERMINATED

Key Thread Methods

Thread t = new Thread(task);
t.setName("processor-1");  // useful for debugging
t.setDaemon(true);         // JVM exits even if daemon threads are running
t.setPriority(Thread.MAX_PRIORITY); // 1-10, default 5 (hint only)
t.start();                 // begin execution
t.join();                  // wait for this thread to finish
t.join(5000);              // wait max 5 seconds
t.interrupt();             // request interruption

// Check interruption
if (Thread.currentThread().isInterrupted()) {
    // clean up and stop
}

// Static methods
Thread.sleep(1000);        // pause current thread (throws InterruptedException)
Thread.yield();            // hint to scheduler to yield CPU
Thread.currentThread();    // reference to currently running thread

Handling InterruptedException

public void run() {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // IMPORTANT: restore interrupt flag
        return; // exit cleanly
    }
}

Never swallow InterruptedException silently — always restore the interrupt flag or re-throw.

Race Conditions

// UNSAFE: counter++ is not atomic (read-modify-write)
private int counter = 0;
public void increment() { counter++; } // race condition!

// SAFE: use AtomicInteger
private AtomicInteger counter = new AtomicInteger();
public void increment() { counter.incrementAndGet(); }

Interview Tips

  1. Know the difference between start() (creates new thread) and run() (executes in the calling thread — does NOT create a new thread).
  2. Daemon threads vs user threads: JVM waits for user threads to finish but not daemon threads. Background tasks (GC, timers) use daemon threads.
  3. Thread.sleep() does NOT release locks — Object.wait() does.

Next

ExecutorService & Thread Pools

AI Tutor

Lesson: Introduction to Threads

Quick actions

AI responses can be inaccurate. Verify critical information.