Java concurrency fundamentals quiz (10 questions)
June 5, 2026
- Java
- Concurrency
- Backend
These questions focus on the concurrency concepts that come up often in mid-level Java interviews: what can go wrong with shared mutable state, which standard APIs solve which problems, and where the common footguns are.
If you want to go one level deeper after this set, pair it with memory model questions so you can explain not only which tool you would choose, but also why threads can or cannot observe each other’s writes.
Question 1
Two threads increment the same int field with count++. What is the most accurate default concern?
Reveal answer
Answer
A race condition can cause lost updates - A race condition can cause lost updates because count++ is a read-modify-write sequence, not one atomic step.
Explanation
Each thread may read the same old value, increment it, and write back the same result. Privacy does not make shared mutation thread-safe. You need synchronization, an atomic type, or another coordination mechanism when multiple threads update shared state.
Example
class Counter {
int count = 0;
void increment() {
count++;
}
} Common interview notes
A common follow-up is when AtomicInteger is enough and when a lock is still needed for compound multi-field updates.
Question 2
You need to run 500 short asynchronous tasks without manually creating 500 threads. Which API is the best starting point?
Reveal answer
Answer
ExecutorService - ExecutorService is the standard starting point because it separates task submission from thread management.
Explanation
Executors let you reuse a bounded pool, queue tasks, and shut down gracefully. Manually creating a thread per task is usually wasteful and harder to control. ThreadLocal solves per-thread state, not task scheduling.
Example
ExecutorService pool = Executors.newFixedThreadPool(8);
pool.submit(() -> processJob());
pool.shutdown(); Common interview notes
Strong answers often mention pool sizing trade-offs and the difference between CPU-bound and IO-bound workloads.
Question 3
A method updates shared mutable state and must allow only one thread in the critical section at a time. Which keyword is the simplest default tool?
Reveal answer
Answer
synchronized - synchronized is the simplest default tool for mutual exclusion around a critical section.
Explanation
synchronized ensures one thread at a time enters the guarded block or method for the same monitor and also provides visibility guarantees on lock release and acquisition. volatile only addresses visibility for single reads and writes, not compound mutations.
Common interview notes
Interviewers may ask you to compare synchronized with ReentrantLock and explain when explicit lock APIs are worth the extra complexity.
Question 4
Which statement about Thread.sleep is correct in Java concurrency discussions?
Reveal answer
Answer
It pauses the thread for at least the requested time without releasing held monitors - Thread.sleep pauses the current thread for at least the requested time and does not release monitors it already holds.
Explanation
Sleeping is only a timing mechanism and should not be treated as a coordination primitive. It does not guarantee scheduling order, and it does not fix races. If a sleeping thread holds a lock, other threads still cannot enter that synchronized region.
Common interview notes
A useful follow-up is why sleep-based tests are flaky and why proper coordination primitives are preferred.
Question 5
You need a thread-safe counter with frequent increments and reads but no broader multi-step invariant. Which choice is the best default?
Reveal answer
Answer
AtomicInteger - AtomicInteger is the best default for a simple shared counter with atomic increments.
Explanation
AtomicInteger provides operations such as incrementAndGet without external locking for the single value. It is a good fit when the shared state is one atomic variable rather than a larger transaction across multiple objects.
Example
AtomicInteger processed = new AtomicInteger();
processed.incrementAndGet(); Common interview notes
Good candidates mention that atomics work well for single-variable coordination but do not replace locks for complex invariants.
Question 6
One thread produces work items and another consumes them in FIFO order. Which collection is the best fit?
Reveal answer
Answer
BlockingQueue - BlockingQueue is the best fit for producer-consumer coordination with ordered handoff.
Explanation
A BlockingQueue provides thread-safe enqueue and dequeue operations and can block when the queue is empty or full depending on the implementation. That maps directly to producer-consumer workflows better than general-purpose collections.
Example
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.put("job-1");
String next = queue.take(); Common interview notes
Follow-ups often cover bounded versus unbounded queues and the backpressure implications of each.
Question 7
You are iterating a collection while many threads read it and only rare writes happen. Which structure is often a good fit?
Reveal answer
Answer
CopyOnWriteArrayList - CopyOnWriteArrayList is often a good fit when reads dominate and writes are rare.
Explanation
It creates a fresh underlying array on each write, so readers can iterate without synchronization and without ConcurrentModificationException in typical cases. That makes reads cheap and predictable, but writes become expensive as the collection grows.
Common interview notes
A strong answer mentions that copy-on-write is a niche optimization, not a general-purpose default for frequently updated collections.
Question 8
You submit a Callable to an ExecutorService and need the result later. Which type usually represents that pending computation?
Reveal answer
Answer
Future - Future represents the pending result of an asynchronous computation submitted to an executor.
Explanation
A Future lets you check completion, block for the result with get, and sometimes cancel the work. It is part of the basic executor model and often appears before interviewers move on to CompletableFuture.
Common interview notes
Expect a follow-up on the limitations of Future, especially around composition and non-blocking orchestration.
Question 9
A thread calls wait on an object monitor. Which condition must already be true?
Reveal answer
Answer
The thread must hold that object's monitor - The thread must hold the object's monitor before calling wait.
Explanation
wait, notify, and notifyAll are monitor methods and must be used inside synchronized code for the same object. Otherwise Java throws IllegalMonitorStateException. When wait is called correctly, it releases the monitor and suspends until notification or interruption.
Common interview notes
Interviewers often ask why wait should be used in a loop that rechecks the condition after wake-up.
Question 10
Which statement about ConcurrentHashMap is most accurate?
Reveal answer
Answer
It is designed for concurrent access without fail-fast iteration on every write - ConcurrentHashMap is designed for concurrent access and its iterators are weakly consistent rather than fail-fast on every write.
Explanation
The implementation prioritizes concurrency and scalable access over a perfectly fixed snapshot view. It does not preserve insertion order or sorted order. Reads are much less constrained than a single global lock design.
Common interview notes
A common follow-up is when weakly consistent iteration is acceptable versus when you should snapshot data explicitly.
Full answer key
Review every answer in one place, with explanations and interview tips below.
1. Two threads increment the same int field with count++. What is the most accurate default concern?
Answer summary
A race condition can cause lost updates — A race condition can cause lost updates because count++ is a read-modify-write sequence, not one atomic step.
Each thread may read the same old value, increment it, and write back the same result. Privacy does not make shared mutation thread-safe. You need synchronization, an atomic type, or another coordination mechanism when multiple threads update shared state.
class Counter {
int count = 0;
void increment() {
count++;
}
} Interview tip: A common follow-up is when AtomicInteger is enough and when a lock is still needed for compound multi-field updates.
2. You need to run 500 short asynchronous tasks without manually creating 500 threads. Which API is the best starting point?
Answer summary
ExecutorService — ExecutorService is the standard starting point because it separates task submission from thread management.
Executors let you reuse a bounded pool, queue tasks, and shut down gracefully. Manually creating a thread per task is usually wasteful and harder to control. ThreadLocal solves per-thread state, not task scheduling.
ExecutorService pool = Executors.newFixedThreadPool(8);
pool.submit(() -> processJob());
pool.shutdown(); Interview tip: Strong answers often mention pool sizing trade-offs and the difference between CPU-bound and IO-bound workloads.
3. A method updates shared mutable state and must allow only one thread in the critical section at a time. Which keyword is the simplest default tool?
Answer summary
synchronized — synchronized is the simplest default tool for mutual exclusion around a critical section.
synchronized ensures one thread at a time enters the guarded block or method for the same monitor and also provides visibility guarantees on lock release and acquisition. volatile only addresses visibility for single reads and writes, not compound mutations.
Interview tip: Interviewers may ask you to compare synchronized with ReentrantLock and explain when explicit lock APIs are worth the extra complexity.
4. Which statement about Thread.sleep is correct in Java concurrency discussions?
Answer summary
It pauses the thread for at least the requested time without releasing held monitors — Thread.sleep pauses the current thread for at least the requested time and does not release monitors it already holds.
Sleeping is only a timing mechanism and should not be treated as a coordination primitive. It does not guarantee scheduling order, and it does not fix races. If a sleeping thread holds a lock, other threads still cannot enter that synchronized region.
Interview tip: A useful follow-up is why sleep-based tests are flaky and why proper coordination primitives are preferred.
5. You need a thread-safe counter with frequent increments and reads but no broader multi-step invariant. Which choice is the best default?
Answer summary
AtomicInteger — AtomicInteger is the best default for a simple shared counter with atomic increments.
AtomicInteger provides operations such as incrementAndGet without external locking for the single value. It is a good fit when the shared state is one atomic variable rather than a larger transaction across multiple objects.
AtomicInteger processed = new AtomicInteger();
processed.incrementAndGet(); Interview tip: Good candidates mention that atomics work well for single-variable coordination but do not replace locks for complex invariants.
6. One thread produces work items and another consumes them in FIFO order. Which collection is the best fit?
Answer summary
BlockingQueue — BlockingQueue is the best fit for producer-consumer coordination with ordered handoff.
A BlockingQueue provides thread-safe enqueue and dequeue operations and can block when the queue is empty or full depending on the implementation. That maps directly to producer-consumer workflows better than general-purpose collections.
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.put("job-1");
String next = queue.take(); Interview tip: Follow-ups often cover bounded versus unbounded queues and the backpressure implications of each.
7. You are iterating a collection while many threads read it and only rare writes happen. Which structure is often a good fit?
Answer summary
CopyOnWriteArrayList — CopyOnWriteArrayList is often a good fit when reads dominate and writes are rare.
It creates a fresh underlying array on each write, so readers can iterate without synchronization and without ConcurrentModificationException in typical cases. That makes reads cheap and predictable, but writes become expensive as the collection grows.
Interview tip: A strong answer mentions that copy-on-write is a niche optimization, not a general-purpose default for frequently updated collections.
8. You submit a Callable to an ExecutorService and need the result later. Which type usually represents that pending computation?
Answer summary
Future — Future represents the pending result of an asynchronous computation submitted to an executor.
A Future lets you check completion, block for the result with get, and sometimes cancel the work. It is part of the basic executor model and often appears before interviewers move on to CompletableFuture.
Interview tip: Expect a follow-up on the limitations of Future, especially around composition and non-blocking orchestration.
9. A thread calls wait on an object monitor. Which condition must already be true?
Answer summary
The thread must hold that object's monitor — The thread must hold the object's monitor before calling wait.
wait, notify, and notifyAll are monitor methods and must be used inside synchronized code for the same object. Otherwise Java throws IllegalMonitorStateException. When wait is called correctly, it releases the monitor and suspends until notification or interruption.
Interview tip: Interviewers often ask why wait should be used in a loop that rechecks the condition after wake-up.
10. Which statement about ConcurrentHashMap is most accurate?
Answer summary
It is designed for concurrent access without fail-fast iteration on every write — ConcurrentHashMap is designed for concurrent access and its iterators are weakly consistent rather than fail-fast on every write.
The implementation prioritizes concurrency and scalable access over a perfectly fixed snapshot view. It does not preserve insertion order or sorted order. Reads are much less constrained than a single global lock design.
Interview tip: A common follow-up is when weakly consistent iteration is acceptable versus when you should snapshot data explicitly.
Try each question on your own, then open "Reveal answer" for the full write-up. For tailored practice and Check feedback on open-ended responses, use PrepAhead in the app - not on blog pages.