Java concurrency questions show up in almost every backend interview.
The goal of this guide is simple: give you short, clean explanations you can say out loud at a whiteboard — without drowning in theory.
This article assumes you’ve already read the basics from:
👉 Concurrency in Java — A Complete Beginner-Friendly Guide
Here, we focus only on interview-style questions and answers — practical, concise, and optimized for real backend interviews.
Use these as templates for your own explanations.
🟦 Section 1 — Core Concepts
Q1. What is concurrency in Java?
Short answer:
Concurrency means multiple tasks making progress at the same time.
Key points:
- JVM achieves concurrency using multiple threads inside the same process.
- Threads share memory → requires careful thread safety.
- Concurrency improves responsiveness and scalability.
Q2. What is parallelism? How is it different from concurrency?
Short answer:
- Concurrency → tasks appear to run together.
- Parallelism → tasks literally run at the same time on multiple CPU cores.
Interview line:
➡ “Concurrency is about structure; parallelism is about execution.”
Q3. What is a thread?
A thread is the smallest unit of execution inside a JVM process.
It has:
- its own stack
- its own program counter
- shared heap memory with other threads
Q4. What is the difference between a process and a thread?
| Process | Thread |
|---|---|
| Has its own memory | Shares memory |
| Expensive to create | Lightweight |
| Heavy context switching | Very fast switching |
| Often multiple per OS | Multiple inside JVM |
Q5. What are the thread states in Java?
- NEW
- RUNNABLE
- BLOCKED
- WAITING
- TIMED_WAITING
- TERMINATED
Important:
➡ RUNNABLE includes both “ready to run” and “running”.
➜ A TERMINATED thread cannot be restarted or reused — calling start() again throws IllegalThreadStateException.
Q6. What is thread scheduling?
The OS scheduler decides which thread runs and for how long.
- It is preemptive (threads can be interrupted).
- It is not predictable — JVM gives no guarantees.
Q7. What is a critical section in Java? How is it different from a resource?
Short answer:
A resource is what multiple threads want to access.
A critical section is the code that accesses that resource and must be executed by only one thread at a time.
Detailed explanation
Developers often confuse these two concepts, but they are not the same. The resource is the shared data. The critical section is the protected code that uses the shared data.
Resource
A resource is the shared data that threads want to read or write.
Examples:
- Shared variable (
counter) - Shared object (
List,Map) - File, socket, or DB connection
- Any shared memory structure
Code example (resource only):
int counter; // shared resource
List<String> list; // shared resource
Critical Section
A critical section is the piece of code that operates on a shared resource and must not be executed by multiple threads at the same time.
Code example (critical section):
synchronized (lock) { // critical section
counter++; // accessing shared resource
}
Comparison Table
(Add this using Gutenberg → Table block)
| Concept | What It Means | Example |
|---|---|---|
| Resource | The shared data that must be protected | Shared variable, shared list |
| Critical Section | The code that accesses/modifies the resource | synchronized block incrementing a value |
Perfect interview explanation
A resource is the shared data; a critical section is the protected code that accesses that data.
🟦 Section 2 — Thread Creation & Execution
Q8. How do you create a thread in Java?
Three primary ways:
- Implement Runnable
- Extend Thread
- Use ExecutorService (recommended)
Q9. Runnable vs Callable — what’s the difference?
| Feature | Runnable | Callable |
|---|---|---|
| Returns value? | ❌ No | ✅ Yes |
| Throws checked exceptions? | ❌ No | ✅ Yes |
| Works with thread pools? | Yes | Best |
Interview line:
➡ “Callable is the modern choice when you need a result.”
Q10. What happens if you call run() instead of start()?
run()→ behaves like a normal method → no new threadstart()→ creates a new OS thread → runsrun()inside it
Q11. Why should we avoid using new Thread()?
Because:
- Threads are expensive
- JVM cannot reuse them
- Hard to manage a large number of threads
- Risk of memory/CPU exhaustion
Use ExecutorService instead.
Q12. What is ExecutorService?
A framework for managing thread pools.
Benefits:
- Reuses threads
- Controls concurrency
- Supports Callable & Future
- Cleaner shutdown
- Better performance under load
🟦 Section 3 — Synchronization & Thread Safety
Q13. What is a race condition?
When two or more threads access shared data and the final result depends on timing.
Q14. What is synchronization?
Synchronization ensures that only one thread executes a critical section at a time.
Tools include:
synchronizedkeyword- Locks
- Atomic variables
Q15. Difference between sleep(), wait(), and yield()?
| Method | Purpose |
|---|---|
sleep() | Pause without releasing lock |
wait() | Releases lock and waits for notify |
yield() | Suggests scheduler to switch threads |
Q16. What is a deadlock?
A situation where two threads wait for each other’s locks and neither proceeds.
Interview tip:
➡ Two locks + two threads → instant deadlock example.
Q17. What is thread starvation?
A thread never gets CPU time because higher-priority threads dominate.
Q18. What is livelock?
Threads are active but make no progress because they continually react to each other.
🟦 Section 4 — Volatile, Locks, and Atomicity
Q19. What does volatile do?
volatile ensures:
- Visibility: updates are seen immediately by other threads
- Ordering: prevents instruction reordering
But:
➡ It does not make operations atomic.
Q20. What is atomicity?
An operation that is all-or-nothing, without interruption.
Example:i++ is not atomic — needs a lock or atomic class.
Q21. What are atomic classes?
Examples include:
AtomicIntegerAtomicLongAtomicBoolean
They provide lock-free, thread-safe operations.
Q22. Synchronized vs Lock — what’s the difference?
| Feature | synchronized | Lock |
|---|---|---|
| Easy to use | ✔ | ❌ More verbose |
| Auto unlock | ✔ | ❌ Must unlock manually |
| Try lock? | ❌ No | ✔ tryLock() |
| Interruptible waits? | ❌ No | ✔ Yes |
Q23. What is ReadWriteLock?
Allows:
- Multiple concurrent readers
- Only one writer
Useful for read-heavy workloads.
🟦 Section 5 — java.util.concurrent Utilities
Q24. What is a Future?
A placeholder for an async result.
Limitations:
- Cannot chain
- Blocking
get() - No composition
Q25. What is CompletableFuture?
A powerful async framework enabling:
- Chaining
- Combining tasks
- Non-blocking pipelines
- Timeouts & error handling
Q26. What are common thread pool types?
- FixedThreadPool
- CachedThreadPool
- SingleThreadExecutor
- ScheduledThreadPool
- ForkJoinPool
Q27. What is a BlockingQueue?
A thread-safe queue that blocks automatically when full/empty.
Perfect for producer-consumer systems.
Q28. What are concurrent collections?
Examples:
ConcurrentHashMapCopyOnWriteArrayListConcurrentLinkedQueue
Designed for multi-threaded environments.
🟦 Section 6 — High-Level and System Design Questions
Q29. How do you avoid deadlocks?
- Acquire locks in a fixed order
- Use
tryLock()with timeouts - Reduce lock scope
- Prefer immutable objects
Q30. How do you design a thread-safe class?
- Make fields final
- Use immutability
- Use concurrent data structures
- Minimize shared state
Q31. How do you improve concurrency performance?
- Reduce lock contention
- Use lock-free algorithms
- Use appropriate thread pool sizes
- Avoid blocking operations
Q32. When should you avoid concurrency?
- When tasks are simple and sequential
- When shared state is unavoidable and complex
- When latency matters more than throughput
🟦 Section 7 — Real-World Scenarios: Choosing Runnable, Callable, or Thread
Q33. In a payment system, how do you choose between Runnable, Callable, and Thread?
Scenario
You’re designing a payment processing service that must:
- Validate card details with Service A
- Fetch a fraud score from Service B
- Check account limits with Service C
All three calls are independent and may take 100–1000ms.
The system must respond in under 800ms.
What this implies
Running these calls sequentially is too slow.
We need parallel execution and we need return values from each call.
Correct choice: Callable + ExecutorService
Callable is ideal because:
- Each task returns a value
- Exceptions can be captured
- ExecutorService manages thread reuse
- Futures allow clean aggregation of results
Interview-ready answer
“A payment decision depends on multiple external calls. I’d call them in parallel using Callable tasks with an ExecutorService. Runnable is insufficient because I need return values, and raw Thread doesn’t scale.”
Q34. In a user signup workflow, when should you use Runnable instead of Callable?
Scenario
When a new user signs up, the system must:
- Send a welcome email
- Write an audit log entry
These operations are important but should not block the HTTP response.
What this implies
We need asynchronous execution, but no return values.
We simply need to “fire and forget.”
Correct choice: Runnable submitted to ExecutorService
Runnable is enough because:
- No result needs to be returned
- No exception propagation is needed
- The main request should complete immediately
Interview-ready answer
“Signup should return quickly, so email and audit logging run asynchronously. Runnable is perfect because I don’t need return values. I’d submit these tasks to an ExecutorService rather than create raw Threads.”
Q35. For a CPU-heavy batch job, how do you choose between Runnable and Callable?
Scenario
A nightly batch job must process millions of records:
- Workload is split into chunks
- Each chunk performs CPU-heavy calculations
- Some chunks may fail
- The job must finish within one hour
- The server has multiple CPU cores
What this implies
This is CPU-bound, and each chunk can run in parallel.
The concurrency level should match the number of cores.
Each chunk may or may not need to return a result.
Correct choice: Runnable or Callable depending on return values
Use Callable when:
- Each batch returns metrics (processed count, error count)
Use Runnable when:
- The batch writes output directly and does not need to return data
In both cases:
Use ExecutorService with a fixed thread pool sized to available cores.
Interview-ready answer
“For CPU-heavy workloads, I’d divide the data into chunks and run them in parallel using a fixed thread pool sized to the machine’s cores. If each chunk needs to return a summary, I’d use Callable. If not, Runnable is enough. Raw Threads are unnecessary and don’t scale.”
🟦 Conclusion
Java concurrency appears in every backend engineering interview.
Use these Q&As as templates for explaining concepts in a clear, confident, senior-level tone.
If you haven’t read the foundational tutorial yet, start here:
👉 Concurrency in Java — A Complete Beginner-Friendly Guide


Did this tutorial help you?
If you found this useful, consider bookmarking Code & Candles or sharing it with a friend.
Explore more tutorials