$ Java Multithreading & Exception Handling — Complete Interview Revision
// 6-7 Yrs Experience — Spring Boot & Microservices Focus
Part I
Java Multithreading
1. Fundamentals & Thread Lifecycle
Quick Reference
Basics
Process, Thread, Lifecycle, Creation
Safety
Race Condition, Sync, Volatile, Atomic, Locks
Coordination
wait/notify, Latch, Barrier, Semaphore
Modern Java
Executor, CompletableFuture, ForkJoin, Concurrent Collections
Legend
Core Concept
Sync / Safety
Executor / Async
Collections / Utilities
Danger Zone (Deadlock/Starvation)
Core Definitions (Say These First)
Process→An independently running application with its own memory space
Thread→Smallest unit of execution, runs inside a process, shares its memory
Multithreading→Multiple threads run concurrently within one process, sharing memory
Concurrency→Multiple tasks make progress in overlapping time (not necessarily the same instant)
Parallelism→Multiple tasks run truly simultaneously on multiple CPU cores
Thread Lifecycle
State Transitions
NEW
→ start() →
RUNNABLE
→
RUNNING
RUNNING
→
BLOCKED / WAITING / TIMED_WAITING
→
TERMINATED
StateMeaning
NEWThread object created, start() not yet called
RUNNABLEEligible to run — moves here after start()
RUNNINGCPU is actively executing this thread
BLOCKEDWaiting to acquire a monitor lock held by another thread
WAITINGWaiting indefinitely — wait(), join() without timeout
TIMED_WAITINGWaiting a fixed time — sleep(), wait(ms), join(ms)
TERMINATEDRun completed (normally or via exception)
2. Thread Creation
Thread Creation Options
OptionNotes
extends ThreadSimplest, but no multiple inheritance — avoid in practice
implements RunnablePreferred — no return value, no checked exceptions
Callable<V>Returns a value, can throw checked exceptions
Future<V>Handle to result of async task — get() blocks
CompletableFutureNon-blocking, chainable, combinable async pipeline
Runnable
ReturnNo return value
ExceptionsNo checked exceptions
Methodrun()
Callable
ReturnReturns a value (V)
ExceptionsCan throw checked exceptions
Methodcall()
3. Thread Safety — Race Condition, Sync, Visibility, Atomicity
Race Condition & Synchronization
Race Condition≥2 threads read-modify-write same shared state concurrently → lost updates
Critical SectionCode block touching shared state; must run exclusively
synchronized methodLocks this (instance monitor) for the whole method
synchronized blocksynchronized(obj){...} — locks only the critical section
static synchronizedLocks the Class object — one lock across all instances
Monitor / Intrinsic LockBuilt-in lock every Java object has; backbone of synchronized
Visibility & Atomicity
volatileGuarantees visibility of latest value across threads — NOT atomicity
AtomicInteger / AtomicLongLock-free, thread-safe counters via incrementAndGet() etc.
AtomicReferenceAtomic updates to object references
CASCompare-And-Swap: read → compare expected → update or retry (lock-free)
Common Comparisons
volatile
GuaranteesVisibility only
CASNo CAS
count++Unsafe
AtomicInteger
GuaranteesVisibility + Atomicity
CASUses CAS internally
count++Safe
4. Locking Mechanisms & Deadlock Management
Locking Mechanisms
ReentrantLockExplicit lock — tryLock(), fairness, interruptibility
ReadWriteLockMultiple readers OR one writer — great for read-heavy caches
StampedLockAdds optimistic read mode — faster than ReadWriteLock
Fair Locknew ReentrantLock(true) — grants lock in request order
tryLock()Attempts lock, returns immediately/with timeout instead of blocking
Deadlock, Starvation, Livelock
DeadlockThreads hold-and-wait on each other's locks in a cycle → all stuck forever
StarvationA thread never gets CPU/lock because others keep getting priority
LivelockThreads keep responding to each other but make no real progress
PreventionConsistent lock ordering, tryLock()+timeout, avoid nested locks
Classic Deadlock Example
// Thread-1 lock(A); lock(B); // Thread-2 (reverse order = deadlock) lock(B); lock(A);
ReentrantLock with tryLock
Lock lock = new ReentrantLock(); if (lock.tryLock(5, TimeUnit.SECONDS)) { try { /* work */ } finally { lock.unlock(); } }
5. Thread Communication — wait() / notify() / notifyAll() / sleep()
MethodBehavior
wait()Releases the lock and waits until notified — must be inside a synchronized block (Object class)
notify()Wakes ONE waiting thread (unspecified which)
notifyAll()Wakes ALL waiting threads
sleep()Pauses the thread but KEEPS the lock (Thread class, not Object)
wait() / notifyAll()
synchronized(lock) { while (!ready) lock.wait(); // proceed after notifyAll() }
wait() vs sleep()
// wait(): releases lock, Object class, needs synchronized // sleep(): keeps lock, Thread class, no synchronized needed
6. Executor Framework & Thread Pools
Executor Framework
ExecutorBase interface — just execute(Runnable)
ExecutorServiceAdds submit(), shutdown(), returns Future
ScheduledExecutorServiceRun tasks after a delay / periodically
FixedThreadPoolFixed N threads, unbounded queue
CachedThreadPoolGrows/shrinks dynamically — risky under heavy load
SingleThreadExecutorOne thread, tasks run sequentially in order
ScheduledThreadPoolFixed pool for scheduled/repeating jobs
Production: ThreadPoolTaskExecutor
@Bean Executor taskExecutor() { ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor(); ex.setCorePoolSize(10); ex.setMaxPoolSize(20); ex.setQueueCapacity(100); ex.initialize(); return ex; }
Why not new Thread()? No pooling/reuse, no lifecycle management, no backpressure/queueing, resource exhaustion risk in production.
7. Concurrent Collections & Producer-Consumer
Concurrent Collections
ConcurrentHashMapBucket/node-level locking — thread-safe map, no full-map lock
CopyOnWriteArrayListCopies array on write — best when reads >> writes
ConcurrentLinkedQueueLock-free, non-blocking FIFO queue
BlockingQueueBlocks on put()/take() when full/empty — Producer-Consumer
ConcurrentSkipListMapThread-safe sorted map, concurrent version of TreeMap
Producer-Consumer (BlockingQueue)
BlockingQueue<Integer> q = new ArrayBlockingQueue<>(10); q.put(1); // producer, blocks if full q.take(); // consumer, blocks if empty
ConcurrentHashMap
ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); map.computeIfAbsent("k", k -> "v");
8. Synchronization Utilities
UtilityPurpose
CountDownLatchOne-time — main thread awaits N workers finishing (not reusable)
CyclicBarrierReusable — all threads wait for each other at a checkpoint
SemaphoreLimits N concurrent threads — DB pool, rate limiting
PhaserAdvanced reusable barrier with dynamic party registration
ExchangerTwo threads swap data at a synchronization point
CountDownLatch
CountDownLatch latch = new CountDownLatch(3); latch.countDown(); // per worker latch.await(); // main thread
Semaphore (Rate Limiting)
Semaphore sem = new Semaphore(5); sem.acquire(); try { /* limited resource */ } finally { sem.release(); }
CountDownLatch vs CyclicBarrier — CountDownLatch is one-time use, parent thread waits; CyclicBarrier is reusable, all threads wait for each other.
9. Fork-Join, Parallel Streams & CompletableFuture
CompletableFuture Chain (Aggregator Pattern)
supplyAsync()
→
thenApply()
→
thenCombine()
→
exceptionally()
Async Task → Transform → Combine Results → Handle Errors
CompletableFuture<User> u = CompletableFuture.supplyAsync( () -> userService.getUser()); CompletableFuture<Order> o = CompletableFuture.supplyAsync( () -> orderService.getOrders()); CompletableFuture.allOf(u, o).join();
ForkJoinPool & Parallel Stream
ForkJoinPoolDivide-and-conquer pool with work-stealing between idle threads
RecursiveTask<V>Fork-join task that returns a result
RecursiveActionFork-join task with no return value
Work StealingIdle worker threads "steal" tasks from busy threads' queues
parallelStream()Uses common ForkJoinPool internally — good for CPU-bound work only
Avoid parallelStream() for: DB Calls, External APIs, Small Collections.
10. ThreadLocal & Spring Boot @Async
ThreadLocal
ThreadLocal<T>Per-thread isolated copy of a variable — no sharing across threads
InheritableThreadLocalChild threads inherit parent's ThreadLocal value
MDC (Logging)Uses ThreadLocal to carry correlation/request-ID through logs
Use cases: User Context, Correlation ID, Request Tracking. Always call .remove() in thread pools to avoid leaks.
Spring Boot @Async
@EnableAsync @Async public CompletableFuture<String> process() { return CompletableFuture .completedFuture("Done"); }
⚠ Will @Async work in a same-class self-invocation call? NO — Spring AOP proxy is bypassed; the method must be called through the Spring-managed bean.
11. Thread Pool Sizing & Kafka Concurrency
Thread Pool Sizing (Frequently Asked)
CPU-Bound Tasks
Threads = CPU Cores + 1
e.g. heavy computation, encryption, image processing
I/O-Bound Tasks
Threads = Cores × (1 + Wait/Compute)
e.g. DB calls, REST API calls, file I/O — usually need larger pools
Kafka Consumer Concurrency (Partitions ≥ Consumers)
@KafkaListener(topics = "orders", concurrency = "3") // 6 Partitions, 3 Consumers Consumer-1 → P0, P1 Consumer-2 → P2, P3 Consumer-3 → P4, P5
One partition is consumed by exactly one consumer within a group — extra consumers beyond partition count sit idle.
12. Production Troubleshooting
High CPU→Thread dump + profiler to find hot loops/threads
Deadlock→Thread dump shows "waiting to lock" cycle
Thread Dump→Snapshot of all thread states/stacks at a point in time
Heap Dump→Snapshot of memory objects — for memory leak analysis
Starvation→Thread never scheduled — check fairness / priorities
Pool Exhaustion→All pool threads busy — queue grows, requests time out
13. Interview Comparisons & Must-Know Code Snippets
synchronizedReentrantLock
JVM managed, auto-releaseManual lock/unlock (try/finally)
No tryLock()tryLock() with timeout
Less flexibleFair locking, interruptible
wait()sleep()
Releases the lockKeeps the lock
Object classThread class
Needs synchronizedNo synchronized needed
HashMapConcurrentHashMap
Not thread-safeThread-safe, bucket-level locks
Race conditions possibleSafe concurrent access
CountDownLatchCyclicBarrier
One-time useReusable
Main thread waits for workersAll threads wait for each other
Runnable Task
class MyTask implements Runnable { public void run() { System.out.println("Running"); } }
Callable + Future
Callable<String> task = () -> "Success"; Future<String> f = executor.submit(task); String result = f.get(); // blocks
Synchronized Method / Block
public synchronized void increment() { count++; } synchronized(this) { count++; }
Volatile Flag (Safe Stop)
private volatile boolean running = true; // running = false; from another thread // visible immediately to the loop thread
AtomicInteger Counter
AtomicInteger count = new AtomicInteger(0); count.incrementAndGet(); count.getAndIncrement();
ExecutorService Basics
ExecutorService ex = Executors.newFixedThreadPool(10); ex.submit(task); ex.shutdown();
ThreadLocal Context
ThreadLocal<String> user = new ThreadLocal<>(); user.set("Pranik"); user.get(); user.remove(); // avoid leaks in pools
CompletableFuture Chain
CompletableFuture.supplyAsync(this::callService) .thenApply(this::process) .exceptionally(ex -> "Fallback");
14. Multithreading — 30-Second Interview Revision
✓Concurrency ≠ Parallelism (overlap vs simultaneous)
✓Thread: NEW→RUNNABLE→RUNNING→(BLOCKED/WAITING/TIMED_WAITING)→TERMINATED
✓Prefer Runnable/Callable over extending Thread
✓Race Condition = unsynchronized shared-state read-modify-write
✓volatile = visibility only, NOT atomicity
✓Atomic classes use CAS — lock-free thread safety
✓ReentrantLock > synchronized: tryLock(), fairness
✓Deadlock = circular wait on locks → prevent via lock ordering
✓wait() releases lock; sleep() keeps lock
✓Avoid new Thread() in enterprise code — use ExecutorService
✓CPU-bound pool size = cores + 1
✓I/O-bound pool size = cores × (1 + wait/compute)
✓parallelStream() uses common ForkJoinPool — avoid for I/O
✓CompletableFuture > Future: non-blocking, chainable
✓ConcurrentHashMap: bucket-level locks, no full-map lock
✓CopyOnWriteArrayList: best when reads >> writes
✓CountDownLatch = one-time; CyclicBarrier = reusable
✓Semaphore = limit N concurrent threads (DB pool, rate limit)
✓ThreadLocal = per-thread isolated data (context, correlation ID)
✓@Async fails on self-invocation — AOP proxy bypassed
✓Kafka: partitions ≥ consumers; extra consumers idle
✓Troubleshooting: thread dump for deadlock/blocking, heap dump for memory
Part II
Exception Handling
15. Exception Handling Basics & Throwable Hierarchy
Throwable Hierarchy
Object └── Throwable (message + cause + stack trace) ├── Error — serious JVM problems, usually unrecoverable └── Exception — application can handle/recover ├── Checked Exception — checked at compile time └── RuntimeException — Unchecked Exception, checked at runtime
Without exception handling: error occurs → program terminates. With it: error occurs → exception caught → alternative logic runs → application continues.
Error vs Exception
ErrorException
Serious JVM problem, app should not handleUnexpected but recoverable situation
OutOfMemoryError, StackOverflowError, NoClassDefFoundErrorIOException, SQLException, ArithmeticException, NullPointerException
Purpose of exception handling: maintain normal program flow, prevent crashes, improve reliability, meaningful error messages, simplify debugging.
16. Checked vs Unchecked Exceptions
Checked Exception
Checked AtCompile Time
HandlingCompiler forces try-catch OR throws
NatureRecoverable
ExamplesIOException, SQLException, ClassNotFoundException, FileNotFoundException, InterruptedException, ParseException
Unchecked Exception
Checked AtRuntime
HandlingCompiler does NOT force handling
NatureUsually a programming mistake
ExamplesNullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, IllegalArgumentException, NumberFormatException, ClassCastException, ConcurrentModificationException
Real Project Scenarios
IOException→Reading a CSV file
SQLException→Database query failure
InterruptedException→Background job interrupted
NumberFormatException→Invalid user input
NullPointerException→Missing API response field
ArithmeticException→Division by zero in business calculation
17. try / catch / finally — Execution Flow
BlockRule
tryContains risky code; only one try block before catch/finally
catchHandles a specific exception; can have multiple catch blocks, ordered specific → generic
finallyAlways executes (exception or not); used for cleanup — close resources, release connections
Multi-Catch (Java 7+)catch(IOException | SQLException e) — less code, better readability
Execution Flow
try
↓ No Exception
Skip catch → finally → Continue
↓ Exception Occurs
Matching catch → finally → Continue
return inside try: finally still executes, then the method returns. System.exit() terminates the JVM — finally will NOT execute. Only one finally is allowed per try.
final vs finally vs finalize()
final→Keyword — cannot change (variable/method/class)
finally→Block — always executes
finalize()→Method — called before GC, deprecated, don't use
18. throw vs throws & Exception Propagation
throw
TypeKeyword — actually throws one exception
UsedInside a method body, creates an exception object
Syntaxthrow new Exception(...);
throws
TypeDeclares possible exceptions in method signature
UsedCan declare multiple, does not itself throw anything
Syntaxvoid readFile() throws IOException
Exception Propagation Flow
main()
→
service()
→
repository()
→
Exception thrown
→ propagates back →
Handled at main()/service()
Checked exceptions must be handled or declared at every level. Unchecked exceptions automatically propagate until caught.
19. Custom & Business Exceptions
Custom Exception Hierarchy
Exception └── BusinessException ├── UserNotFoundException ├── PaymentFailedException └── CourseNotFoundException
Create custom exceptions for: User Not Found, Insufficient Balance, Course Already Exists, Certificate Expired, Invalid OTP, Payment Failed.
Checked Custom Exception
ExtendsException
HandlingCompiler forces handling, recoverable
Runtime Custom Exception
ExtendsRuntimeException
HandlingPreferred for business validation — Spring Boot standard
Technical vs Business Exception
Technical→IOException, SQLException, Network Failure, Timeout
Business→Duplicate User, Invalid Password, Invalid OTP, Course Closed
20. Try-With-Resources, Suppressed & Exception Chaining
Try-With-Resources (Java 7+)
Open Resource
↓
Use Resource
↓
Resource Automatically Closed (finally not required)
Works with AutoCloseable/Closeable: FileInputStream, BufferedReader, Scanner, Connection, PreparedStatement, ResultSet, Socket. Benefits: less boilerplate, no resource leaks, recommended for JDBC.
Suppressed Exception & Exception Chaining
Suppressed Exception → occurs when a primary exception already exists and another exception occurs while closing a resource; it gets attached to the primary exception Exception Chaining → wraps one exception inside another to preserve the original cause (e.g. SQLException → RepositoryException → ServiceException → Controller)
Why chaining? Preserve root cause, better debugging, layer separation — enterprise standard.
Stack Trace
Sequence of method calls leading to the exception. Read bottom → top; the root cause is usually the last "Caused by".
21. Spring Boot Exception Handling
Global Exception Flow
Client Request
→
Controller
→
Service
→
Repository
→ Exception →
Global Exception Handler
→
JSON Error Response → Client
Local vs Global Exception Handling
Local (try-catch)Global (@ControllerAdvice)
Inside method, repeated code, hard to maintainCentralized, reusable, recommended
@ControllerAdvice vs @RestControllerAdvice
@ControllerAdvice@RestControllerAdvice
MVC + REST, needs @ResponseBody for JSON= @ControllerAdvice + @ResponseBody, returns JSON automatically — preferred for REST APIs
@ResponseStatus vs ResponseStatusException
@ResponseStatusResponseStatusException
Static mapping on a custom exception classDynamic HTTP status without creating a custom exception class
@ExceptionHandler — Example Mappings
UserNotFoundException404
DuplicateUserException409
IllegalArgumentException / Validation Exception400
AccessDeniedException403
AuthenticationException401
Unhandled Exception500
ProblemDetail (Spring Boot 3 · RFC 9457) & Standard Error Response
ProblemDetail Fields
type · title · status · detail · instance
Standard, REST-friendly, extensible error format provided by Spring Boot 3.
Recommended Error Response Fields
timestamp · status · error · message · path · traceId · requestId · errors (validation)
22. Validation Exceptions & HTTP Status Cheat Sheet
Validation Flow
@RequestBody
→
@Valid
→
MethodArgumentNotValidException
→
Global Handler → Validation Errors
Common annotations: @NotNull @NotBlank @NotEmpty @Size @Email @Pattern @Positive @Min @Max @Past @Future
ExceptionOccurs When
MethodArgumentNotValidException@RequestBody validation fails
ConstraintViolationException@PathVariable / @RequestParam validation fails
BindExceptionObject binding fails (form data, query params)
HttpMessageNotReadableExceptionInvalid/malformed JSON, wrong data type
HttpRequestMethodNotSupportedExceptionWrong HTTP method (e.g. GET instead of POST)
NoHandlerFoundExceptionRequested URL not found → 404
HTTP Status Cheat Sheet
200OK
201Created
204No Content
400Bad Request
401Unauthorized
403Forbidden
404Not Found
405Method Not Allowed
409Conflict
422Unprocessable Entity (optional)
500Internal Server Error
503Service Unavailable
Real Project Scenarios
User Registration→Duplicate Email → 409 Conflict
Login→Invalid Credentials → 401 Unauthorized
Certificate Portal→Certificate Not Found → 404
Course Enrollment→Course Full → 400 Bad Request
Payment→Gateway Timeout → 503 Service Unavailable
Database→Constraint Violation → 409 Conflict
23. Best Practices & Anti-Patterns
✓ Best Practices
✓Catch specific exceptions first, most specific → most generic
✓Never catch Throwable; never ignore exceptions
✓Keep try blocks small; always close resources
✓Use try-with-resources for JDBC/file IO
✓Log exceptions properly; log once, handle once
✓Create business-specific exceptions; extend RuntimeException for business errors
✓Preserve root cause via exception chaining
✓Use @RestControllerAdvice + standard ErrorResponse DTO
✓Map correct HTTP status codes; validate input using @Valid
✓Don't expose internal stack trace to clients; include correlation/trace ID
✗ Anti-Patterns
✗ Catch Exception / Throwable everywhere
✗ Empty catch block
✗ Printing stack trace in production
✗ Using exceptions for normal control flow
✗ Throwing generic Exception
✗ Swallowing exceptions silently
✗ Returning null instead of throwing an exception
Logging strategy: Business Exception → WARN, Validation Error → INFO, Technical Exception → ERROR. Never log passwords, OTPs, JWTs, or other sensitive data.
24. Exception Handling — One-Liner Revision
›Throwable → Parent of Errors & Exceptions
›Error → JVM Problem
›Exception → Recoverable Problem
›Checked Exception → Compile Time
›Unchecked Exception → Runtime
›try → Risky Code
›catch → Handle Exception
›finally → Cleanup Block
›Multi-Catch → One catch for multiple exceptions
›throw → Explicitly throw exception
›throws → Declare possible exception
›Propagation → Travels to caller until handled
›Custom Exception → Business-meaningful exception
›Try-With-Resources → Auto resource cleanup
›AutoCloseable → Interface enabling auto-close
›Suppressed Exception → Exception during resource close
›Exception Chaining → Wrap original exception (preserve cause)
›Stack Trace → Method call history to the exception
›@ControllerAdvice → Global exception handler
›@RestControllerAdvice → REST global handler (JSON)
›@ExceptionHandler → Handles a specific exception
›@ResponseStatus → Static HTTP status
›ResponseStatusException → Dynamic HTTP status
›ProblemDetail → Standard Spring Boot 3 error format
›MethodArgumentNotValidException → Request body validation
›ConstraintViolationException → Parameter validation
›AccessDeniedException → 403
›AuthenticationException → 401
›Global Handler → Central error management
›final vs finally vs finalize() → constant / cleanup block / deprecated GC hook
25. Final Combined Revision Flow
15-Minute Multithreading Flow
Fundamentals → Thread Lifecycle
↓
Thread Creation (Runnable/Callable)
↓
Thread Safety (Sync/Volatile/Atomic/CAS)
↓
Locking & Deadlock
↓
Executor Framework & Thread Pools
↓
Concurrent Collections & Sync Utilities
↓
Fork-Join / CompletableFuture / @Async / Kafka
15-Minute Exception Handling Flow
Throwable Hierarchy → Checked/Unchecked
↓
try / catch / finally
↓
throw vs throws → Propagation
↓
Custom Exception → Try-With-Resources
↓
@ControllerAdvice → @ExceptionHandler
↓
ProblemDetail → Validation Exceptions
↓
Logging → Production Best Practices
Interviewers Expect You To Explain
✓ Thread Lifecycle & Internal Working of Executors ✓ Race Conditions & Synchronization Strategies ✓ Deadlock Causes & Prevention ✓ CompletableFuture / Parallel Streams Trade-offs ✓ Checked vs Unchecked Exception Design Choices ✓ Global Exception Handling in Spring Boot ✓ Exception Chaining & Root-Cause Preservation ✓ Real Production Troubleshooting (deadlocks, thread dumps, pool exhaustion)