AlgoMaster Logo

Fizz Buzz Multithreaded

medium8 min readUpdated August 31, 2026
Listen to this chapter
Unlock Audio

Four threads share one FizzBuzz instance and produce the Fizz Buzz sequence from 1 through n:

  • Thread A calls fizz(printFizz) and must output "fizz" for numbers divisible by 3 but not 5.
  • Thread B calls buzz(printBuzz) and must output "buzz" for numbers divisible by 5 but not 3.
  • Thread C calls fizzbuzz(printFizzBuzz) and must output "fizzbuzz" for numbers divisible by both 3 and 5.
  • Thread D calls number(printNumber) and must output every remaining number.

The supplied callbacks perform the output. Your task is to synchronize the four methods so the callbacks are invoked in the correct order and every value from 1 through n is produced exactly once.

The judge creates the shared object, starts all four threads, and calls each method once. Your implementation should coordinate those calls rather than create threads itself.

The judge also preloads the standard concurrency and callback APIs for each supported language. You do not need to add import, include, or using statements.

Example 1:

Input:

Output:

Example 2:

Input:

Output:

Constraints

  • 1 <= n <= 50
  • The four methods are called concurrently on the same FizzBuzz instance.
  • Each supplied callback is thread-safe and must be called only for the value assigned to that method.

Starter Code

Understanding the Problem

The four methods cannot independently loop over 1 through n. If they do, their callbacks may run in an arbitrary scheduler order, producing duplicates or placing "buzz" before an earlier number.

The methods need one shared position, current, that represents the next value to output. A method may advance that position only when the current value belongs to it.

MethodMay run when
fizzcurrent % 3 == 0 and current % 5 != 0
buzzcurrent % 5 == 0 and current % 3 != 0
fizzbuzzcurrent % 15 == 0
numbercurrent % 3 != 0 and current % 5 != 0

Exactly one row matches any value, so exactly one method is responsible for each position.

Synchronization Strategy

Use a lock with a condition variable and initialize current to 1.

Each method repeatedly:

  1. Acquires the shared lock.
  2. Waits while current <= n but the current value belongs to another method.
  3. Returns if current > n, waking any threads that are still waiting.
  4. Invokes its callback, increments current, and wakes all waiting methods.

The callback and increment happen while holding the lock. This makes outputting a value and advancing the sequence one atomic step from the other methods' point of view.

Waking all waiters is important because the next value may belong to any one of the other three methods.

Correctness

The lock allows only one method to inspect, output, and advance current at a time. A method waits unless its predicate matches current, and the four predicates are mutually exclusive and collectively cover every integer. Therefore, only the callback assigned to current can run.

After that callback runs, the same thread increments current before releasing the lock. Consequently, no other method can output the old value, and no method can output a later value first.

Starting from current = 1, each successful iteration outputs exactly the representation required for that value and advances current by one. By induction, the callbacks produce the correct Fizz Buzz sequence in order through n. Once current becomes n + 1, all methods return, so no extra output is produced.

Code

Complexity Analysis

Every value is output exactly once.

  • Time complexity: O(n) total callback work.
  • Space complexity: O(1) shared synchronization state, excluding the four judge-owned threads and output buffer.