Multithreading in Java — Comprehensive
Explanation
Introduction
Multithreading is one of the most important parts of Java because Java was designed from the beginning
with built-in support for concurrent programming.
To truly understand multithreading, you must understand several related concepts:
1. Process vs Thread
2. Concurrency vs Parallelism
3. Java Memory Model (JMM)
4. Thread Lifecycle
5. Thread Creation
6. Synchronization
7. Race Conditions
8. Locks and Monitors
9. Volatile
10. Atomic Variables
11. Thread Communication
12. Executor Framework
13. Thread Pools
14. Callable and Future
15. Fork/Join Framework
16. CompletableFuture
17. Concurrent Collections
18. Deadlocks
19. Livelocks
20. Starvation
21. Thread Safety
22. Immutable Objects
23. Performance Considerations
24. Virtual Threads (Modern Java)
25. Best Practices
These topics are interconnected and form the complete picture of Java multithreading.
1. What is a Thread?
A thread is the smallest unit of execution inside a process.
1
A process is an independent running program.
Example
• Chrome Browser = Process
• One tab loading a webpage = Thread
• Another tab rendering graphics = Thread
A process can contain multiple threads.
Visualization
Process
│
├── Thread 1
├── Thread 2
├── Thread 3
└── Thread 4
Shared Among Threads
• Heap Memory
• Method Area
• Open Files
• System Resources
Private To Each Thread
• Stack
• Program Counter (PC)
• Local Variables
2. Why Multithreading?
Without multithreading:
Task A
↓
Task B
↓
Task C
Everything executes sequentially.
2
With multithreading:
Task A ──┐
├── Execute concurrently
Task B ──┤
│
Task C ──┘
Benefits
• Better CPU utilization
• Faster execution
• Responsive applications
• Background processing
• Improved scalability
Common Uses
• Web servers
• Databases
• Game engines
• Operating systems
• Android applications
3. Process vs Thread
Process Thread
Independent program Unit of execution
Heavyweight Lightweight
Separate memory Shared memory
Costly creation Cheaper creation
Communication expensive Communication easier
4. Concurrency vs Parallelism
Many developers confuse these concepts.
3
Concurrency
Managing multiple tasks during the same period.
Single CPU:
Task A
Task B
Task A
Task B
Task A
The CPU rapidly switches between tasks.
Appears simultaneous.
Parallelism
Actual simultaneous execution.
Multi-core CPU:
Core 1 → Task A
Core 2 → Task B
Tasks truly execute at the same time.
5. Java Thread Model
Java threads are generally mapped to native operating system threads.
Thread t = new Thread();
The JVM requests the operating system to create a corresponding native thread.
Java relies on:
• OS Scheduler
• OS Context Switching
• OS Thread Priorities
4
6. Thread Lifecycle
Java defines the following thread states:
[Link]
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
NEW
Thread created but not started.
Thread t = new Thread();
RUNNABLE
[Link]();
Ready to execute.
May or may not currently be running.
BLOCKED
Waiting to acquire a monitor lock.
synchronized(lock) {
}
WAITING
Waiting indefinitely.
5
Examples:
wait();
join();
TIMED_WAITING
Waiting with timeout.
Examples:
sleep(1000);
wait(1000);
join(1000);
TERMINATED
Execution completed.
7. Creating Threads
Method 1: Extend Thread
class MyThread extends Thread {
public void run() {
[Link]("Running");
}
}
MyThread t = new MyThread();
[Link]();
Method 2: Implement Runnable
class MyTask implements Runnable {
public void run() {
[Link]("Running");
6
}
}
Thread t = new Thread(new MyTask());
[Link]();
Preferred because Java supports only single inheritance.
Lambda Style
Thread t = new Thread(() -> {
[Link]("Running");
});
[Link]();
8. start() vs run()
Incorrect
[Link]();
No new thread is created.
Current thread executes the method.
Correct
[Link]();
Creates a new thread.
The JVM eventually invokes run() .
7
9. Thread Scheduling
The scheduler determines:
• Which thread runs
• When it runs
• How long it runs
Never assume:
[Link]();
[Link]();
means:
t1 runs before t2
Java provides no such guarantee.
10. Context Switching
CPU switches between threads.
Thread A
↓
Save State
Thread B
↓
Save State
Thread A
Saved state includes:
• Registers
• Program Counter
• Stack Information
Excessive switching introduces overhead.
8
11. Shared Data Problem
int count = 0;
Two threads execute:
count++;
Internally:
Read count
Add 1
Write count
Possible execution:
Thread A reads 0
Thread B reads 0
Thread A writes 1
Thread B writes 1
Expected:
Actual:
12. Race Condition
Occurs when:
• Multiple threads access shared data
9
• At least one thread modifies it
• Outcome depends on execution timing
Example:
balance -= 100;
Banking systems must avoid race conditions.
13. Synchronization
Ensures controlled access to shared mutable state.
synchronized(this) {
count++;
}
The protected code is called the critical section.
14. Monitor Lock
Every Java object has an associated monitor.
Object lock = new Object();
synchronized(lock) {
}
A thread must acquire the monitor before entering.
15. Synchronized Methods
public synchronized void increment() {
count++;
}
10
Equivalent to:
synchronized(this) {
count++;
}
16. Static Synchronization
public static synchronized void test() {
}
Locks:
[Link]
Not individual instances.
17. Java Memory Model (JMM)
One of the most important concurrency concepts.
The JMM defines:
• Visibility
• Ordering
• Atomicity
between threads.
It provides consistent behavior across hardware architectures.
18. Main Memory and Working Memory
Threads may cache variables locally.
11
Main Memory
↑↓
Thread A Cache
Thread B Cache
A thread's updates may not immediately become visible to another thread.
This is a visibility problem.
19. Volatile Keyword
volatile boolean running = true;
If one thread updates:
running = false;
Other threads immediately observe the change.
Guarantees
• Visibility
• Ordering Constraints
Does Not Guarantee
• Atomicity
Unsafe:
volatile int count;
count++;
20. Atomicity
Atomic operations occur completely or not at all.
12
Atomic:
x = 5;
Non-atomic:
count++;
Because it consists of:
Read
Modify
Write
21. Atomic Classes
Package:
[Link]
Example:
AtomicInteger count =
new AtomicInteger();
Increment safely:
[Link]();
Often avoids explicit synchronization.
22. Inter-Thread Communication
Methods:
13
wait()
notify()
notifyAll()
Declared in Object .
23. wait()
synchronized(lock) {
[Link]();
}
Behavior:
• Releases monitor
• Enters waiting state
24. notify()
[Link]();
Wakes one waiting thread.
25. notifyAll()
[Link]();
Wakes all waiting threads.
26. Producer-Consumer Problem
Producer:
14
Creates Data
Consumer:
Consumes Data
Requires coordination.
Modern Java usually uses:
BlockingQueue
instead of raw wait() and notify() .
27. Deadlock
Two or more threads wait forever.
Example:
Thread A:
Lock 1
Wait Lock 2
Thread B:
Lock 2
Wait Lock 1
Result:
Deadlock
15
28. Coffman Conditions
Deadlock requires all four:
1. Mutual Exclusion
2. Hold and Wait
3. No Preemption
4. Circular Wait
Removing any one prevents deadlock.
29. Livelock
Threads continue reacting but make no progress.
Example:
You move left
I move right
You move right
I move left
Both remain active.
Neither advances.
30. Starvation
A thread never receives required resources.
Causes include:
• Unfair locking
• Priority abuse
• Resource monopolization
16
31. ReentrantLock
Lock lock = new ReentrantLock();
[Link]();
try {
// critical section
}
finally {
[Link]();
}
Advantages:
• Fairness support
• tryLock()
• Interruptible lock acquisition
32. ReadWriteLock
ReadWriteLock rw =
new ReentrantReadWriteLock();
Allows:
Many Readers
One Writer
Useful for read-heavy workloads.
33. Semaphore
Semaphore s =
new Semaphore(3);
Only three threads can enter simultaneously.
17
Typical uses:
• Connection pools
• Resource throttling
34. CountDownLatch
CountDownLatch latch =
new CountDownLatch(3);
Workers:
[Link]();
Waiting thread:
[Link]();
35. CyclicBarrier
[Link]();
Multiple threads meet at a synchronization point and continue together.
36. Executor Framework
Instead of:
new Thread(...)
Use:
ExecutorService executor;
18
Separates task submission from thread management.
37. Thread Pools
ExecutorService ex =
[Link](5);
Benefits:
• Thread reuse
• Better performance
• Controlled resource consumption
38. Callable
Runnable cannot return a result.
Callable can.
Callable<Integer> task =
() -> 10;
39. Future
Represents a pending computation result.
Future<Integer> f =
[Link](task);
Retrieve result:
Integer result = [Link]();
19
40. CompletableFuture
Modern asynchronous programming API.
CompletableFuture
.supplyAsync(() -> fetch())
.thenApply(data -> process(data))
.thenAccept([Link]::println);
Supports:
• Chaining
• Combining
• Non-blocking workflows
41. Fork/Join Framework
Designed for divide-and-conquer algorithms.
Split
↓
Process
↓
Merge
Implemented through:
ForkJoinPool
42. Parallel Streams
[Link]()
.forEach([Link]::println);
Uses the ForkJoin framework internally.
Not always faster.
20
Performance depends on:
• Data size
• Core count
• Task complexity
43. Concurrent Collections
Package:
[Link]
Examples:
ConcurrentHashMap
ConcurrentHashMap<K,V>
CopyOnWriteArrayList
CopyOnWriteArrayList<E>
BlockingQueue
BlockingQueue<E>
Provide thread-safe alternatives to standard collections.
44. ThreadLocal
ThreadLocal<Integer> local =
new ThreadLocal<>();
Each thread maintains its own value.
21
Common uses:
• Request context
• User session data
• Database connections
45. Immutable Objects
Immutable objects cannot change after creation.
Example:
String
Advantages:
• Naturally thread-safe
• No synchronization required
• No race conditions
46. Thread Safety
A class is thread-safe when multiple threads can use it concurrently without corrupting state.
Achieved through:
• Synchronization
• Immutability
• Atomic classes
• Concurrent collections
47. Happens-Before Relationship
Core concept of the Java Memory Model.
If:
22
unlock()
happens-before
lock()
then changes become visible.
Important happens-before relationships:
• Monitor Release → Monitor Acquire
• Volatile Write → Volatile Read
• [Link]() → Thread Execution
• Thread Completion → [Link]()
• Final Field Initialization Guarantees
This is the foundation of memory visibility in Java.
48. Virtual Threads (Java 21+)
Introduced by Project Loom.
Traditional Model:
1 Java Thread
=
1 OS Thread
Virtual Thread Model:
Millions of Java Threads
↓
Mapped onto a Small Pool
of OS Threads
Example:
23
[Link](() -> {
[Link]("Hello");
});
Benefits:
• Massive scalability
• Simpler concurrency model
• Excellent for I/O-bound applications
49. Common Mistakes
• Calling run() instead of start()
• Forgetting unlock() in finally blocks
• Synchronizing on the wrong object
• Using volatile for atomicity
• Excessive synchronization
• Creating too many threads
• Ignoring thread pools
• Blocking inside synchronized sections
50. Interview-Level Mental Model
Process
↓
Threads
↓
Shared Memory
↓
Race Conditions
↓
Synchronization
↓
Locks & Monitors
↓
Java Memory Model
↓
Volatile
↓
Atomic Variables
↓
24
Thread Communication
↓
Executors
↓
Thread Pools
↓
CompletableFuture
↓
Concurrent Collections
↓
Deadlocks
↓
Virtual Threads
Key Areas for Deep Mastery
For professional-level Java concurrency expertise, focus especially on:
1. Java Memory Model (JMM)
2. Happens-Before Relationships
3. Synchronization and Locking
4. Executor Framework
5. Concurrent Collections
6. CompletableFuture
7. Virtual Threads
8. Performance Analysis and Scalability
These concepts explain not just how multithreading works, but why concurrent Java programs behave
correctly—or fail—in production systems.
25