108 Essential Java Multithreading Interview Questions and Answers
This comprehensive guide compiles 108 common Java multithreading interview questions, covering the purpose of concurrency, thread creation methods, lifecycle nuances, synchronization utilities, memory visibility, thread safety levels, debugging techniques, executor frameworks, concurrent collections, atomic operations, lock implementations, and best‑practice recommendations.
Purpose of Multithreading
Multithreading leverages multi‑core CPUs to improve throughput, prevents blocking when a single thread waits for I/O, and simplifies modeling of complex tasks by decomposing them into independent subtasks.
Creating Threads
Two primary ways to create a thread in Java are extending Thread or implementing Runnable. Implementing Runnable is preferred because it reduces coupling and follows interface‑driven design.
Thread Lifecycle: start() vs run()
Calling start() creates a new OS thread and executes run() concurrently; invoking run() directly runs the method synchronously in the current thread.
Runnable vs Callable
Runnablereturns void and cannot throw checked exceptions, while Callable returns a generic result and works with Future to retrieve the outcome or cancel the task.
Synchronization Utilities
CyclicBarrier : reusable barrier; all threads wait until the last arrives, then all proceed.
CountDownLatch : one‑time latch; threads wait until the count reaches zero, then all are released.
Semaphore : limits concurrent access to a code block; a permit count of 1 behaves like a mutex.
Lock (ReentrantLock) : offers fair/unfair policies, tryLock, timed lock acquisition, and interruptible locking.
Memory Visibility and volatile
volatileguarantees that reads see the latest write and prevents instruction reordering, but it does not provide atomicity for compound actions. It is often combined with CAS to achieve lock‑free updates.
Thread Safety Levels
Immutable objects (e.g., String, wrapper classes) are inherently thread‑safe.
Absolute thread safety: classes that are safe under any usage (e.g., CopyOnWriteArrayList).
Relative thread safety: typical synchronized collections like Vector where individual operations are atomic but combined actions may still need external synchronization.
Non‑thread‑safe classes (e.g., ArrayList, HashMap).
Thread Dump and Debugging
On Linux, obtain the process ID with jps or ps -ef | grep java, then use jstack <pid> or send SIGQUIT ( kill -3 <pid>) to generate a thread dump. The Thread.getStackTrace() method can also retrieve a stack trace for a specific thread.
Thread Pools and Executor Framework
Creating a new thread for each task is expensive; thread pools reuse worker threads, limit concurrency, and provide scheduling features. The Executor interface defines task execution, while ExecutorService adds lifecycle management and result retrieval via Future. ThreadPoolExecutor allows custom pool sizes and rejection policies.
Concurrent Collections and Locks
ConcurrentHashMap : uses segment (pre‑JDK8) or CAS‑based bucket locking (JDK8+) to allow high concurrency.
SynchronizedMap : locks the entire map, limiting scalability.
CopyOnWriteArrayList : creates a new array on each write, providing lock‑free reads at the cost of memory and write latency.
ReadWriteLock : separates read (shared) and write (exclusive) locks to improve read‑heavy workloads.
Atomic Operations and CAS
CAS (Compare‑And‑Swap) atomically updates a variable when its current value matches an expected value. It underpins classes in java.util.concurrent.atomic (e.g., AtomicInteger, AtomicReference). ABA problems are mitigated with AtomicStampedReference or AtomicMarkableReference. Drawbacks include high CPU usage under contention and inability to compose multi‑variable atomic actions.
Lock Implementations
ReentrantLockis a class‑based lock offering features unavailable with the synchronized keyword, such as fairness control, timed tryLock, and interruptible lock acquisition. synchronized is simpler but always non‑fair and cannot be queried for lock state.
Best Practices
Prefer the smallest possible synchronized block to reduce contention.
Use ThreadLocal for per‑thread expensive objects (e.g., SimpleDateFormat).
When using wait(), always call it inside a loop that re‑checks the condition to guard against spurious wake‑ups.
Never call notify() or notifyAll() outside a synchronized block; the JVM will throw IllegalMonitorStateException.
Prefer Executor over manual thread creation for better resource management and scalability.
Additional Topics
Thread priorities are advisory and OS‑dependent; setting them does not guarantee execution order. Daemon threads run background services and do not prevent JVM shutdown. The Thread.yield() method hints to the scheduler that the current thread is willing to pause.
public class UnReentrant {
Lock lock = new ReentrantLock();
public void outer() {
lock.lock();
inner();
lock.unlock();
}
public void inner() {
lock.lock();
// do something
lock.unlock();
}
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
