Interview
Concurrency & Multithreading — Interview Questions (150+)
Detailed Questions
1. Process vs thread?
- Short: Processes have isolated memory; threads share the process heap.
- Detailed: Threads are lightweight, share heap/metaspace but have their own stack and PC. Communication between threads is via shared memory (needs synchronization); processes use IPC.
- Example: A web server uses many threads in one JVM process.
2. How do you create threads in Java?
- Short: Implement Runnable/Callable, or use an Executor; Java 21 adds virtual threads.
- Detailed: Prefer
Runnable/Callablesubmitted to anExecutorServiceover subclassingThread.Thread.ofVirtual()creates virtual threads. - Example:
Executors.newFixedThreadPool(4).submit(task);
3. start() vs run()?
- Short: start() spawns a new thread; run() executes on the current thread.
- Detailed: Calling
run()directly is just a normal method call—no concurrency.start()schedules the thread and the JVM callsrun()on the new thread. - Example:
new Thread(task).start();
4. What is a race condition?
- Short: Result depends on unsynchronized timing of threads.
- Detailed: Two threads access shared mutable state and at least one writes, with no happens-before ordering.
count++(read-modify-write) is the classic example. - Example: Two threads incrementing a shared int lose updates.
5. synchronized vs volatile?
- Short: synchronized = mutual exclusion + visibility; volatile = visibility only.
- Detailed:
synchronizedprovides atomicity for the block and establishes happens-before via the monitor.volatileguarantees reads see the latest write but does NOT make compound actions (x++) atomic. - Example: Use volatile for a
boolean runningflag; synchronized/atomic for counters.
6. What is the Java Memory Model and happens-before?
- Short: Rules guaranteeing visibility/ordering across threads.
- Detailed: Happens-before relations (program order, monitor lock/unlock, volatile write/read, thread start/join) ensure one action's effects are visible to another. Without them, reordering and stale reads are legal.
- Example: Unlocking a monitor happens-before another thread locking it.
7. What is a deadlock and how to avoid it?
- Short: Threads wait forever on each other's locks; avoid with lock ordering.
- Detailed: Four Coffman conditions: mutual exclusion, hold-and-wait, no preemption, circular wait. Avoid by consistent global lock ordering, tryLock with timeout, or lock-free structures.
- Example: T1 holds A waits B; T2 holds B waits A.
8. ExecutorService benefits over raw threads?
- Short: Pooling, lifecycle, task submission, results.
- Detailed: Thread creation is expensive; pools reuse threads, bound concurrency, queue tasks, and return
Futures. Lifecycle viashutdown/awaitTermination. - Example:
var pool = Executors.newFixedThreadPool(8);
9. Callable vs Runnable?
- Short: Callable returns a value and can throw checked exceptions.
- Detailed:
Runnable.run()returns void;Callable.call()returns a result wrapped in aFuture. - Example:
Future<Integer> f = pool.submit(() -> 42);
10. What is CompletableFuture?
- Short: Composable, non-blocking async computations.
- Detailed: Build pipelines with
thenApply/thenCompose/thenCombine, handle errors withexceptionally/handle, coordinate withallOf/anyOf. Runs on ForkJoinPool by default or a supplied executor. - Example:
supplyAsync(this::load).thenApply(this::parse);
11. What are virtual threads (Java 21)?
- Short: Lightweight JVM-scheduled threads for massive concurrency.
- Detailed: Virtual threads mount onto carrier (platform) threads; blocking a virtual thread unmounts it, so millions can exist cheaply. Ideal for blocking I/O; not for CPU-bound work. Avoid
synchronizedaround blocking calls (pinning)—useReentrantLock. - Example:
Executors.newVirtualThreadPerTaskExecutor().
12. Atomic classes and CAS?
- Short: Lock-free thread-safe ops via Compare-And-Swap.
- Detailed:
AtomicInteger/Long/Referenceuse hardware CAS to update without locks.incrementAndGet,compareAndSet,accumulateAndGet.LongAdderscales better under high contention. - Example:
counter.incrementAndGet();
13. ReentrantLock vs synchronized?
- Short: Lock adds tryLock, fairness, interruptibility, multiple conditions.
- Detailed:
synchronizedis simpler and auto-released.ReentrantLockallowstryLock(timeout), fairness policy,lockInterruptibly, and multipleConditions—at the cost of manualunlock()in finally. - Example:
lock.lock(); try{...} finally{ lock.unlock(); }
14. ConcurrentHashMap internals?
- Short: Bucket-level CAS + synchronized bins; lock-free reads.
- Detailed: No global lock; atomic per-key ops (
compute,merge,computeIfAbsent). Weakly consistent iterators. No null keys/values. - Example: Atomic counter map via
merge(key,1,Integer::sum).
15. wait/notify vs Condition vs BlockingQueue?
- Short: Low-level signaling vs lock conditions vs ready-made coordination.
- Detailed:
wait/notifyrequire holding the monitor and a loop guarding spurious wakeups.Conditionpairs with locks.BlockingQueuehandles producer/consumer waiting for you. - Example: Prefer
BlockingQueuefor producer/consumer.
Rapid-Fire (Q → A)
- Thread states? → NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
- sleep vs wait? → sleep keeps lock; wait releases it.
- wait must be in? → synchronized block.
- notify vs notifyAll? → Wake one vs all waiters.
- spurious wakeup fix? → Loop the condition check.
- join()? → Wait for a thread to die.
- yield()? → Hint to scheduler.
- interrupt()? → Request cancellation.
- isInterrupted()? → Check interrupt flag.
- InterruptedException meaning? → Blocking call was interrupted.
- daemon thread? → Doesn't block JVM exit.
- setDaemon timing? → Before start().
- thread priority reliable? → No (platform-dependent).
- main thread daemon? → No.
- volatile guarantees? → Visibility + ordering, not atomicity.
- volatile for counters? → Insufficient.
- double-checked locking needs? → volatile field.
- happens-before via volatile? → Write before read.
- final field safe publication? → Yes, if no this-escape.
- atomicity of long/double? → Non-volatile may tear (pre-JMM guarantees aside).
- AtomicInteger op? → CAS.
- LongAdder benefit? → Less contention than AtomicLong.
- AtomicReference use? → Lock-free object swap.
- compareAndSet? → Atomic conditional update.
- ABA problem? → Value changes back; use AtomicStampedReference.
- ReentrantLock reentrant? → Same thread re-acquires.
- tryLock benefit? → Avoid blocking/deadlock.
- fair lock cost? → Lower throughput.
- lockInterruptibly? → Abort waiting on interrupt.
- ReadWriteLock? → Many readers or one writer.
- StampedLock? → Optimistic reads.
- Condition await/signal? → Lock-based wait/notify.
- Semaphore? → Permit-limited access.
- binary semaphore? → Mutex-like (1 permit).
- CountDownLatch? → One-shot wait for N.
- CyclicBarrier? → Reusable barrier with action.
- Phaser? → Flexible multi-phase barrier.
- Exchanger? → Two threads swap data.
- CompletableFuture default pool? → Common ForkJoinPool.
- supplyAsync vs runAsync? → Returns value vs void.
- thenApply vs thenCompose? → map vs flatMap.
- thenCombine? → Merge two futures.
- exceptionally? → Recover from error.
- handle? → Process result or error.
- allOf? → Wait for all.
- anyOf? → First to complete.
- get() vs join()? → Checked vs unchecked exceptions.
- Future.cancel? → Attempt cancellation.
- ForkJoinPool algorithm? → Work-stealing.
- RecursiveTask vs RecursiveAction? → Returns vs void.
- fork/join threshold? → Avoid over-splitting.
- commonPool size? → CPUs - 1 by default.
- parallelStream pool? → Common ForkJoinPool.
- Executors.newFixedThreadPool? → Bounded workers.
- newCachedThreadPool? → Elastic, unbounded.
- newSingleThreadExecutor? → Serial.
- newScheduledThreadPool? → Delayed/periodic.
- newVirtualThreadPerTaskExecutor? → Virtual thread per task.
- shutdown vs shutdownNow? → Graceful vs interrupt running.
- awaitTermination? → Block until done/timeout.
- RejectedExecutionHandler? → Policy when queue full.
- ThreadPoolExecutor core params? → core/max/keepAlive/queue/handler.
- Unbounded queue risk? → OOM, ignored max pool.
- SynchronousQueue use? → Direct handoff pools.
- ThreadFactory use? → Name/daemon threads.
- ThreadLocal purpose? → Per-thread state.
- ThreadLocal leak? → In pools without remove().
- InheritableThreadLocal? → Child inherits value.
- ScopedValue (preview)? → Safer ThreadLocal alternative.
- BlockingQueue put/take? → Block on full/empty.
- offer/poll timeout? → Bounded waiting.
- ArrayBlockingQueue? → Bounded array.
- LinkedBlockingQueue? → Optionally bounded.
- PriorityBlockingQueue? → Ordered, unbounded.
- DelayQueue? → Time-delayed elements.
- ConcurrentLinkedQueue? → Lock-free.
- CopyOnWriteArrayList? → Snapshot reads.
- ConcurrentSkipListMap? → Concurrent sorted.
- produce/consume tool? → BlockingQueue.
- deadlock detection? → jstack thread dump.
- livelock? → Active but no progress.
- starvation? → Thread denied resources.
- priority inversion? → Low-priority holds lock needed by high.
- lock ordering? → Prevents circular wait.
- lock granularity? → Coarse vs fine trade-offs.
- lock striping? → Multiple locks per structure.
- optimistic locking? → Version/CAS, retry.
- pessimistic locking? → Lock upfront.
- immutable + concurrency? → Inherently thread-safe.
- thread-safe singleton? → enum/holder idiom.
- safe publication? → final, volatile, synchronized, concurrent collection.
- data race definition? → Unsynchronized conflicting access.
- memory visibility issue? → Stale cached values.
- piggybacking? → Reuse existing happens-before.
- why not Thread.stop? → Unsafe (deprecated).
- cooperative cancellation? → Interrupt + checks.
- busy-wait downside? → Wastes CPU.
- backoff strategy? → Reduce contention.
- false sharing? → Cache line contention.
- @Contended? → Pads to avoid false sharing.
- virtual thread carrier? → Platform thread it runs on.
- pinning cause? → synchronized/native during block.
- pinning fix? → ReentrantLock.
- virtual thread for CPU work? → No benefit.
- structured concurrency (preview)? → Treat tasks as a unit.
- thread per request model? → Scales with virtual threads.
- CompletableFuture vs virtual threads? → Async pipelines vs simple blocking code.
- blocking call on FJP? → Starves pool (use managedBlocker).
- ManagedBlocker? → Tell FJP about blocking.
- concurrent counter best? → LongAdder.
- AtomicLong vs LongAdder? → Single var vs striped cells.
- thread confinement? → Keep data in one thread.
- stack confinement? → Local variables.
- immutable object publication? → Always safe.
- happens-before of thread start? → start() before run actions.
- happens-before of join? → run actions before join returns.
- double-checked locking pattern? → volatile + null check twice.
- when to use synchronized? → Simple mutual exclusion.
- when to use locks? → Need tryLock/conditions/fairness.
- when to use atomics? → Single-variable counters/flags.
- when to use concurrent collections? → Shared maps/queues.
- when to use CompletableFuture? → Async composition.
- when to use virtual threads? → High-concurrency blocking I/O.
- when to use ForkJoin? → Recursive CPU-bound splitting.
- CountDownLatch reuse? → No (one-shot).
- CyclicBarrier reuse? → Yes.
- Phaser dynamic parties? → Yes.
- Semaphore release without acquire? → Adds permits.
- fairness in semaphore? → Optional FIFO.
- blocking vs non-blocking algorithm? → Locks vs CAS/lock-free.
- lock-free vs wait-free? → Some progress vs guaranteed per-op progress.
- memory barrier? → Orders memory operations.
- store/load barrier? → Ordering primitives.
- volatile read cost? → Cheap read, ordered.
- contended lock cost? → Context switches.
- thread dump shows? → Stacks, lock holders, deadlocks.
- CPU 100% one thread? → Likely busy loop.
- high context switching? → Too many threads/contention.
- tuning pool size (CPU-bound)? → ~#cores.
- tuning pool size (I/O-bound)? → Higher / virtual threads.
- Little's law use? → Concurrency = throughput × latency.
- graceful shutdown steps? → shutdown, awaitTermination, shutdownNow.
- handle InterruptedException? → Restore flag or propagate.
- swallow interrupt? → Anti-pattern.
- synchronized on String/Integer? → Bad (shared/cached).
- synchronized on this leak? → Exposes lock; use private lock.
- double locking on different monitors? → Deadlock risk.
- concurrency testing tools? → jcstress, stress tests.
- reproduce race? → Hard; use stress + invariants.
- golden rule? → Prefer immutability and high-level concurrency utilities over low-level locks.