Java Concurrency: The Interview Questions That Trip People Up
volatile, synchronized, ReentrantLock, happens-before — these concepts trip up even experienced engineers. Here's a clear explanation of each.
Concurrency questions separate mid-level from senior engineers in interviews. Here are the concepts that come up most frequently.
Q1: What's the difference between synchronized and ReentrantLock?
synchronized is simpler — it's built into the language and automatically releases the lock. ReentrantLock is more flexible:
ReentrantLock lock = new ReentrantLock();
if (lock.tryLock(1, TimeUnit.SECONDS)) { // timed wait
try {
// critical section
} finally {
lock.unlock(); // must unlock manually
}
}
Use synchronized by default. Use ReentrantLock when you need timed locking, interruptible locking, or multiple condition variables.
Q2: What does volatile actually guarantee?
volatile guarantees visibility, not atomicity. It ensures a write to a volatile variable is immediately visible to all threads. But it does NOT make compound operations atomic.
volatile int counter = 0;
counter++; // NOT atomic — this is read-modify-write
Use AtomicInteger for atomic increments. Use volatile only for a single-field flag.
Q3: Explain the happens-before relationship
The Java Memory Model defines happens-before (HB) guarantees. If action A happens-before B, then B sees all writes made by A.
Key HB relationships:
- Unlock of a monitor → lock of the same monitor
- Write to a volatile → subsequent read of the same volatile
Thread.start()→ any action in the started thread- Any action in a thread →
Thread.join()returns
Q4: What is a ConcurrentHashMap and when would you use it over HashMap?
ConcurrentHashMap allows concurrent reads and a configurable number of concurrent writes without locking the entire map. In Java 8+, it uses a segment-level lock approach.
Use it when multiple threads read and write to the map concurrently. Never use Collections.synchronizedMap(new HashMap<>()) — it serialises all operations.
Related Posts
JDK 27 Is Here: What You Get Just by Upgrading (and What Needs --enable-preview)
JDK 27 went GA on 15 September 2026 with 9 JEPs. G1 everywhere, compact object headers, post-quantum TLS and JFR redaction change behaviour with zero code changes; lazy constants, primitive patterns, structured concurrency and the PEM API are previews. What each one means, with working Java examples.
Java Garbage Collection Explained: G1, ZGC and How to Choose
How the JVM finds garbage, why generations matter, what G1 and ZGC actually do, and a practical way to pick and tune a collector for your service.
Virtual Threads in Java 21: When They Help and When They Don't
Virtual threads make blocking code scale to hundreds of thousands of concurrent tasks — but only for I/O-bound work. How they work, how to use them in Spring Boot, and the pitfalls.
HashMap Internals: How put() and get() Really Work
Buckets, hash spreading, collisions, treeification and resizing — a step-by-step look inside java.util.HashMap, and why equals() and hashCode() must agree.