Cosmic Module

J

Qubits of DPK

March 14, 2026

Core Java

Layman Explanation

A restaurant kitchen has multiple chefs working simultaneously — one making soup, one grilling, one preparing dessert. That's multithreading — multiple tasks executing concurrently in the same program.

What is a Thread?

The smallest unit of execution within a process. A program can have multiple threads running concurrently.
javascript
QUBITS OF DPK
1Process (Java Program)
23├── Thread 1 (main thread)
4├── Thread 2
5├── Thread 3
6└── Thread 4
7
8All share Heap memory
9Each has own Stack

Creating Threads — Two Ways

Way 1: Extend Thread

java
QUBITS OF DPK
1class MyThread extends Thread {
2    @Override
3    public void run() {
4        for (int i = 0; i < 5; i++) {
5            System.out.println(getName() + ": " + i);
6        }
7    }
8}
9
10MyThread t1 = new MyThread();
11MyThread t2 = new MyThread();
12t1.start();   // starts new thread, calls run()
13t2.start();

Way 2: Implement Runnable (Preferred)

java
QUBITS OF DPK
1class MyTask implements Runnable {
2    @Override
3    public void run() {
4        for (int i = 0; i < 5; i++) {
5            System.out.println(Thread.currentThread().getName() + ": " + i);
6        }
7    }
8}
9
10Thread t1 = new Thread(new MyTask());
11Thread t2 = new Thread(new MyTask());
12t1.start();
13t2.start();

Why Runnable over Thread?

javascript
QUBITS OF DPK
11. Java = single inheritance, if you extend Thread, can't extend anything else
22. Runnable separates task from thread mechanism
33. Can reuse same Runnable with multiple threads
44. Works with ExecutorService (production standard)

Thread Priority & Sleep

java
QUBITS OF DPK
1Thread t1 = new Thread(task1);
2Thread t2 = new Thread(task2);
3
4t1.setPriority(Thread.MAX_PRIORITY);   // 10
5t2.setPriority(Thread.MIN_PRIORITY);   // 1
6// JVM tries to respect priority but no guarantee!
7
8// Sleep — pause current thread
9try {
10    Thread.sleep(1000);   // sleep 1 second
11} catch (InterruptedException e) {
12    e.printStackTrace();
13}

Race Condition

When multiple threads access shared data simultaneously and the final result depends on thread execution order.
java
QUBITS OF DPK
1class Counter {
2    int count = 0;
3
4    void increment() {
5        count++;   // NOT atomic! Read-Increment-Write = 3 steps
6    }
7}
8
9// Two threads both increment 1000 times
10// Expected: 2000
11// Actual: could be 1800, 1950, anything! — race condition

Fix: synchronized

java
QUBITS OF DPK
1class Counter {
2    int count = 0;
3
4    synchronized void increment() {   // only one thread at a time!
5        count++;
6    }
7}

Thread States

javascript
QUBITS OF DPK
1NEWRUNNABLERUNNINGTERMINATED
23              BLOCKED/WAITING/TIMED_WAITING
4
5NEWThread created, not started
6RUNNABLEReady to run, waiting for CPU
7RUNNINGCurrently executing
8BLOCKEDWaiting for a lock (synchronized block)
9WAITINGwait() called, waiting for notify()
10TIMED_WAITINGsleep() or wait(timeout) called
11TERMINATEDrun() completed

Production Use Case

java
QUBITS OF DPK
1// Production standard: ExecutorService (not raw threads)
2ExecutorService executor = Executors.newFixedThreadPool(10);
3
4for (int i = 0; i < 100; i++) {
5    executor.submit(() -> {
6        processRequest();
7    });
8}
9
10executor.shutdown();
11// Thread pool reuses threads — much more efficient than creating new threads
12// Used in: web servers, Kafka consumers, batch processing

️ All Traps

java
QUBITS OF DPK
1// Trap 1 — Calling run() instead of start()
2t1.run();    // ❌ runs in CURRENT thread, not new thread!
3t1.start();  // ✅ creates new thread
4
5// Trap 2 — Starting thread twice
6t1.start();
7t1.start();  // ❌ IllegalThreadStateException!
8
9// Trap 3 — count++ is not atomic
10// Must synchronize or use AtomicInteger
11AtomicInteger count = new AtomicInteger(0);
12count.incrementAndGet();   // ✅ thread safe
13
14// Trap 4 — Thread priority not guaranteed
15// JVM/OS may ignore priority hints
16
17// Trap 5 — Deadlock
18// Thread A locks Resource1, waits for Resource2
19// Thread B locks Resource2, waits for Resource1
20// Both wait forever!

Interview Answer (SDE-2)

"A thread is the smallest unit of execution. Java creates threads by extending Thread or implementing Runnable — Runnable is preferred since Java supports single class inheritance and it separates task logic from thread mechanics. start() creates a new thread and calls run(); calling run() directly just executes in the current thread. Race conditions occur when multiple threads access shared mutable state — synchronized keyword ensures only one thread enters a block at a time. Thread states: New, Runnable, Running, Blocked, Waiting, Timed Waiting, Terminated. In production, always use ExecutorService thread pools rather than raw threads."

Interview Questions & MAANG-Level Answers

Q1. What is the difference between Thread and Runnable?
Thread is a class; Runnable is a functional interface. Extending Thread: class MyTask extends Thread — can't extend any other class (single inheritance limit). Implementing Runnable: class MyTask implements Runnable — can still extend another class, and separates task logic from threading mechanism. Runnable is preferred: same task can run on different threads, works with ExecutorService, and is more testable. Lambda makes Runnable even simpler: new Thread(() -> doWork()).start().
Q2. What is the difference between start() and run()?
start() creates a NEW OS thread and calls run() in that thread — truly concurrent execution. run() executes in the CURRENT thread — no new thread created, sequential execution. Critical mistake: t1.run() appears to work but executes synchronously in the calling thread. Always use start() for multithreading. You can verify: Thread.currentThread().getName() inside run() — with start() it shows "Thread-0"; with run() it shows "main".
Q3. What is a race condition and how do you fix it?
Race condition: when multiple threads access shared mutable data simultaneously and the result depends on thread execution order. Example: count++ is 3 operations (read, increment, write) — two threads can both read 5, both increment to 6, both write 6 — increment lost. Fixes: (1) synchronized method/block — mutual exclusion. (2) AtomicInteger.incrementAndGet() — lock-free atomic operation. (3) volatile — for visibility but not atomicity. (4) Immutable objects — no state to race on.
Q4. What is synchronized keyword?
synchronized ensures only ONE thread executes the protected code at a time. Works via an intrinsic lock (monitor) on an object. Methods: synchronized void method() — locks on this. Blocks: synchronized(lockObject) {} — finer-grained control. Drawback: serializes access, reduces concurrency. Alternative: ReentrantLock for tryLock, timeout, and fairness. In production: prefer ConcurrentHashMap over Hashtable, AtomicInteger over synchronized counters for better throughput.
Q5. What is a deadlock?
Deadlock: two or more threads are permanently blocked, each waiting for a lock held by the other:
javascript
QUBITS OF DPK
1Thread A: holds Lock1, waits for Lock2
2Thread B: holds Lock2, waits for Lock1
3Both wait forever!
Prevention: (1) Always acquire locks in the same ORDER across all threads. (2) Use tryLock() with timeout. (3) Use ReentrantLock. (4) Minimize synchronized scope. Detection: thread dumps (jstack), JVM profilers. In production, deadlocks are notoriously hard to reproduce — design lock ordering upfront.
Q6. What are thread states?
New → thread created, not started. Runnable → start() called, ready to run (includes running on CPU). Blocked → waiting to acquire a synchronized lock. Waiting → wait() or join() called, indefinite wait. Timed_Waiting → sleep(ms), wait(ms), join(ms) — waiting with timeout. Terminated → run() completed or exception. You can check state via thread.getState(). Thread dumps show all thread states — critical for debugging production issues.
Q7. What is ExecutorService and why use it over raw threads?
ExecutorService is a thread pool manager in java.util.concurrent. Problems with raw threads: creating/destroying threads is expensive (MB per thread), uncontrolled thread count can crash JVM. ExecutorService maintains a pool of reusable threads:
java
QUBITS OF DPK
1ExecutorService executor = Executors.newFixedThreadPool(10);
2executor.submit(() -> processRequest());
3executor.shutdown();
Benefits: thread reuse (no create/destroy overhead), bounded concurrency (max 10 threads), task queuing, Future for results, graceful shutdown. In production (Spring Boot), use @Async with configured ThreadPoolTaskExecutor.
Q8. What is the difference between sleep() and wait()?
sleep(): Thread.sleep(ms) — pauses current thread for specified time, does NOT release any locks held, resumes automatically after timeout. wait(): Object.wait() — called on a lock object inside synchronized block, RELEASES the lock, pauses until notify()/notifyAll() is called (plus optional timeout). sleep() is for time-based pauses; wait() is for inter-thread communication (producer-consumer pattern). wait() must be in synchronized block; sleep() can be anywhere.