Java Concurrency Quiz: Threads, Locks and Executors Practice
Test Java concurrency with 15 questions and three programs on threads, synchronized, volatile, executors, atomics, ConcurrentHashMap and CompletableFuture.
- Course: Java study plan
- Module: Concurrency
- Kind: Checkpoint — cleared at 70%
- Reading time: 30 min
- Runtime: OpenJDK 18
Checkpoint — Concurrency is the checkpoint that closes the Concurrency module: a graded quiz and whole-program exercises, passed at 70%.
Instructions
This checkpoint covers threads and the interrupt protocol, races and synchronized, the Java Memory Model with volatile and safe publication, executors and Futures, ReentrantLock, atomics and the concurrent collections, CompletableFuture, and the coordination tools — latch, barrier, semaphore and blocking queue.
How it works. Fifteen questions and three programs; 70% on the questions and every program accepted clears the module.
Before you start, make sure you can answer:
start()versusrun(), and how a thread is stopped politely.- Why
count++is a race, and the two guaranteessynchronizedgives. - What
volatiledoes and does not do, and why double-checked locking needs it. - Which happens-before edge makes results written by a worker visible after
join(). - Fixed versus cached pool, what
Future.get()throws, and the shutdown sequence. - Why
ConcurrentHashMap.mergeremoves the check-then-act race a synchronisedHashMaphas. thenApplyversusthenCompose, and which thread runs athenXstage.CountDownLatchversusCyclicBarrier, and how a poison pill ends a consumer.
The programs are a parallel row-sum on a fixed pool with results in order, a bank that transfers money between accounts under per-account locks acquired in a global order, and a phased simulation on a CyclicBarrier whose barrier action reports each round.
Common questions
Which happens-before edge makes a worker's results visible after join()?
Every action in a thread happens-before another thread's join() on it returns. So once join() returns, everything the worker wrote — an array slot, a field — is visible to the joining thread without any further synchronisation.
Why does ConcurrentHashMap merge remove the check-then-act race?
merge reads the current value, applies the function and writes the result as one atomic operation per key. With a synchronised HashMap, get and put are two separately locked calls, and another thread can update the key between them.
How do you transfer money between two accounts without deadlock?
Lock both accounts in one global order — for example the smaller account id first — whichever direction the money moves. Two transfers in opposite directions then request the locks in the same order and cannot each hold one while waiting for the other.
Exercises
Row sums on a pool
Read r, c and a pool size p, then an r × c matrix of integers. On a fixed pool of p threads, submit one Callable<Long> per row with invokeAll, then print row <i>: <sum> for every row in order and total=<sum of all>. Shut the pool down, await termination, and print terminated=true.
Example: 2 3 2 then 1 2 3 / 4 5 6 →
row 0: 6
row 1: 15
total=21
terminated=trueTransfers with ordered locks
Read an integer n and n opening balances, then t and t transfers from to amount. Give each account its own ReentrantLock. Run every transfer on its own thread; a transfer locks the two accounts in ascending index order (lower index first — the rule that makes deadlock impossible), moves the money (balances may go negative), and unlocks both in finally blocks. Join all, then print balances=<Arrays.toString>, total=<sum> and preserved=<total equals opening total>.
Example: 3 then 100 50 0, 3 then 0 1 30, 1 2 60, 2 0 10 →
balances=[80, 20, 50]
total=150
preserved=trueRounds at the barrier
Read k (parties), r (rounds) and k integer values. Create a CyclicBarrier(k, action) whose action prints round <j>: total=<running total> — it runs once per round, on the last thread to arrive. Each of the k threads, for rounds j = 1 … r, adds value × j to a shared AtomicLong and then await()s the barrier. Join all threads and print final=<total>. After round j the total is Σvalues × (1 + 2 + … + j) — the barrier makes that deterministic.
Example: 2 3 then 1 2 →
round 1: total=3
round 2: total=9
round 3: total=18
final=18In this module: Concurrency
← CompletableFuture and the coordination tools · Bytes and characters — streams, readers and encodings →