Problem 7 FizzBuzz Multithreading Problem
Four threads, one ordered output — coordinated by a shared counter
Four threads each own one job: print the number, print "fizz" (n%3==0, not %5), "buzz" (n%5==0, not %3), or
"fizzbuzz" (n%15==0). They must cooperate so the combined output is exactly 1 2 fizz 4 buzz fizz 7 … in
order. The mechanism is a single shared counter current guarded by a lock + condition: each thread
waits until current is a value that belongs to it, prints, advances the counter, and
wakes the others. The earlier version was broken twice over — the method was named Solution() and printed
the literal string "Solution" on multiples of 15, and the driver never joined its threads, so
the program could exit before finishing.
Correct Java
import java.util.concurrent.locks.*;
import java.util.function.IntConsumer;
class FizzBuzz {
private final int n;
private int current = 1;
private final Lock lock = new ReentrantLock();
private final Condition cv = lock.newCondition();
FizzBuzz(int n) { this.n = n; }
private void run(java.util.function.IntPredicate mine, Runnable print) throws InterruptedException {
while (true) {
lock.lock();
try {
while (current <= n && !mine.test(current)) cv.await(); // not my turn
if (current > n) return; // done
print.run();
current++;
cv.signalAll();
} finally { lock.unlock(); }
}
}
public void fizz(Runnable p) throws InterruptedException { run(i -> i%3==0 && i%5!=0, p); }
public void buzz(Runnable p) throws InterruptedException { run(i -> i%5==0 && i%3!=0, p); }
public void fizzbuzz(Runnable p) throws InterruptedException { run(i -> i%15==0, p); }
public void number(IntConsumer p) throws InterruptedException {
while (true) {
lock.lock();
try {
while (current <= n && (current%3==0 || current%5==0)) cv.await();
if (current > n) return;
p.accept(current);
current++;
cv.signalAll();
} finally { lock.unlock(); }
}
}
}
// driver: start all four threads, then join EACH so main waits for completion.
Correct Go
Go expresses the same coordination with sync.Mutex + sync.Cond, and a
sync.WaitGroup replaces the explicit joins.
type FizzBuzz struct{ n, cur int; mu sync.Mutex; cv *sync.Cond }
func (f *FizzBuzz) step(mine func(int) bool, print func(int)) {
for {
f.mu.Lock()
for f.cur <= f.n && !mine(f.cur) { f.cv.Wait() }
if f.cur > f.n { f.mu.Unlock(); return }
print(f.cur); f.cur++; f.cv.Broadcast()
f.mu.Unlock()
}
}
// number: mine = func(i int) bool { return i%3!=0 && i%5!=0 }
// wg.Add(4); go each step; wg.Wait()
Worked schedule for n = 15 (who prints each i)
| i | Predicate true | Thread that prints | Output token |
|---|---|---|---|
| 1 | not ÷3, not ÷5 | number | 1 |
| 2 | number | number | 2 |
| 3 | ÷3 only | fizz | fizz |
| 4 | number | number | 4 |
| 5 | ÷5 only | buzz | buzz |
| 6 | ÷3 only | fizz | fizz |
| … | … | … | … |
| 15 | ÷3 and ÷5 | fizzbuzz only | fizzbuzz |
At i=15, fizz and buzz predicates must be false (they check ÷3-not-÷5 and ÷5-not-÷3). Only
fizzbuzz matches; after it prints, current++ and signalAll let the others re-check and park
until their next hit. Wrong exclusive predicates → double print or hang.
Pitfalls
while (!mine) await()must be a loop, not anif— a thread can wake (signalAll) on a value that still isn't its turn (a spurious-ish wakeup), and must re-check.- Every worker also needs the
current > nexit check inside the loop, or threads hang at the end. - The driver must
joinall four threads (Java) /wg.Wait()(Go), or output is truncated.
When four threads are the wrong answer
This is a coordination exercise, not a throughput pattern. If you only need correct FizzBuzz output, a single
sequential loop that switches on i%15 / i%3 / i%5 is simpler and strictly faster: the four threads here
serialize almost entirely through the one lock — only one of them may act at each i — so you pay context
switches and condition signalling to gain nothing. Put a number on it: the critical section is the entire
per-i body (check predicate, print, advance, signal), so the serial fraction is ≈ 1. Amdahl's law then
caps speedup at 1/(serial fraction) ≈ 1× no matter how many threads or cores you add — you have
bought zero parallelism and spent an extra ~3 signalAll wake-and-recheck cycles per number (the three
threads that were not whose turn it is each wake, re-test, and re-park). That is the honest crossover: the
multithreaded version is strictly slower than the one-line sequential loop for every value of n, and is
justified only as an exercise in condition-variable coordination. Defend the counter+condition design only when the
constraint really is "four threads, each owning one predicate." One thing it is not a good fit for: four BlockingQueues of
pre-routed tokens would just reintroduce a single sequencer deciding which queue to feed each step, which defeats the point
of letting all four threads observe the shared counter themselves.
Takeaways
- Order is enforced by a guarded shared counter: wait-until-mine, print, advance,
signalAll. - Guard the wait in a
whileloop; always include the termination check. - Join/Wait for every worker so the program doesn't exit early.
Re-authored for correctness for this guide (the prior version printed "Solution" and never joined its threads). Pattern: LeetCode 1195 "Fizz Buzz Multithreaded". See also: Condition Variables, Mutex Lock.
🤖 Don't fully get this? Learn it with Claude
Stuck on Problem 7 FizzBuzz Multithreading Problem? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Problem 7 FizzBuzz Multithreading Problem** (Concurrency). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Problem 7 FizzBuzz Multithreading Problem** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Problem 7 FizzBuzz Multithreading Problem**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Problem 7 FizzBuzz Multithreading Problem**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.