HardπŸ‘€ 3-5 yearsπŸ‘€ 8-15 years 3 min read Updated Aug 24, 2026

Producer-Consumer with wait() and notifyAll() β€” No BlockingQueue

Asked inAmazonGoogleMicrosoftDeloitte
#producer consumer#wait notify#synchronized#guarded blocks
Report issue

⚑ Short Answer

Wrap a fixed-size buffer in a synchronized class. A producer calls wait() while the buffer is full; a consumer calls wait() while it's empty. After adding or removing an item, call notifyAll() to wake any thread that might now be able to proceed. This is exactly the guarded-block mechanism ArrayBlockingQueue implements internally β€” interviewers ask for it by hand specifically to check you understand wait/notify, not just that you know the java.util.concurrent class name.

β˜•Coffee Chat Question

Concept Made Simple

β€œHow do you implement a producer-consumer queue with wait() and notifyAll() (not BlockingQueue)?”

🧠Mind Map Answer

Remember It Faster

This is the standard guarded-block pattern applied to a bounded buffer: producers block while it's full, consumers block while it's empty, and every state change (a successful add or remove) wakes up threads that might now be able to proceed.

java
class BoundedBuffer<T> {
    private final Queue<T> queue = new LinkedList<>();
    private final int capacity;
    BoundedBuffer(int capacity) { this.capacity = capacity; }

    synchronized void put(T item) throws InterruptedException {
        while (queue.size() == capacity) {
            wait(); // releases the lock, blocks until notified
        }
        queue.add(item);
        notifyAll(); // wake any consumer(s) waiting on "not empty"
    }

    synchronized T take() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        T item = queue.remove();
        notifyAll(); // wake any producer(s) waiting on "not full"
        return item;
    }
}
Producer blocks when→queue.size() == capacity
Consumer blocks when→queue.isEmpty()
After put/take→notifyAll() wakes threads waiting on the OTHER condition
Why while, not if→spurious wakeups + multiple waiters — must re-check after waking

notifyAll() (not notify()) matters here specifically because producers and consumers share the same monitor. notify() wakes one arbitrary waiting thread, which might be another producer that still can't proceed instead of the consumer that just became unblocked. notifyAll() wakes everyone; each re-checks its own while condition, and only the ones that can actually proceed continue β€” the rest go straight back to waiting.

⌨️Hands-on Keyboard

Learn by Doing

java
BoundedBuffer<Integer> buf = new BoundedBuffer<>(10);
new Thread(() -> { try { buf.put(42); } catch (InterruptedException ignored) {} }).start();
new Thread(() -> { try { System.out.println(buf.take()); } catch (InterruptedException ignored) {} }).start();

πŸ”₯What If?

Think Beyond the Expected

You used notify() instead of notifyAll() and the buffer occasionally hangs under load β€” why?

With multiple producers and consumers waiting on the same monitor, notify() can wake a thread that still can't proceed β€” say it wakes another blocked producer while a waiting consumer was the one that actually needed the signal. That producer re-checks its while condition, fails it, and goes straight back to wait(), and the consumer that needed waking never gets notified. notifyAll() avoids this by waking every waiter so each can independently re-check its own condition.

πŸ˜‚Real World

ArrayBlockingQueue and LinkedBlockingQueue implement essentially this pattern internally β€” production code uses a Condition per direction instead of raw wait/notify for efficiency, but the logic is the same guarded-block shape. Building this by hand once is what lets you actually reason about BlockingQueue's behavior instead of treating it as a black box.

πŸ—£οΈReal Talk from Guru

I still ask this in interviews even though nobody should write it in production β€” BlockingQueue exists precisely so you don't have to. What I'm checking for is whether someone understands why wait() has to be in a while loop and why notifyAll() beats notify() here, because that understanding is what lets them correctly reason about deadlocks and missed signals anywhere else wait/notify shows up.

🎯Interviewer's Expectation

Keywords they're listening for:

βœ“ wait() releases the lock and blocks; must be called inside synchronizedβœ“ always re-check the condition in a while loop, never an ifβœ“ notifyAll() over notify() when multiple different conditions share one monitorβœ“ this is the mechanism BlockingQueue implements internally

⚠️Common Mistakes

  • βœ—Using if instead of while around wait() β€” misses spurious wakeups and skips the re-check
  • βœ—Calling wait()/notify() outside a synchronized block (throws IllegalMonitorStateException)
  • βœ—Using notify() when multiple different wait conditions share one monitor

βœ…Best Practices

  • βœ“Always loop on the condition with while, never if
  • βœ“Use notifyAll() unless you can prove only one type of waiter exists on the monitor
  • βœ“Reach for java.util.concurrent's BlockingQueue in real production code β€” build this by hand mainly to internalize the mechanism

πŸ”Follow-up Questions

  • 1Why must wait() be called inside a synchronized block?
  • 2What's a spurious wakeup, and why does that alone require a while loop?
  • 3How does this relate to ArrayBlockingQueue's actual implementation?
  • 4When, if ever, is notify() safe to use instead of notifyAll()?

🧩Related Technologies

wait/notifysynchronizedArrayBlockingQueueguarded blocks

Continue Learning with AI

Take this question deeper with your favourite AI assistant. Pick a depth, copy the prompt, or open it directly β€” AI is your learning companion, not a shortcut.

Plain-language foundations

I'm preparing for a software engineering interview and want to understand this from scratch, as a beginner.

Topic: Coordination (Multithreading)
Interview question: "How do you implement a producer-consumer queue with wait() and notifyAll() (not BlockingQueue)?"

Please:
1. Explain the core idea in simple, plain language, using an everyday analogy.
2. Define any technical terms you use.
3. Walk through one small, concrete example.
4. Finish with a single sentence I can easily remember.

Keep the tone friendly and assume I'm new to this topic.

Was this answer helpful?

Support our platform by exploring our recommended products.

As an Amazon affiliate, purchases through these links may earn us a small commission β€” at no extra cost to you. It helps keep Full Stack Interview Guru free.

Related Questions