0

I recently saw the following implementation of enqueue for a BlockingQueue (source)

public synchronized void enqueue(Object item)
throws InterruptedException  {
  while(this.queue.size() == this.limit) {
    wait();
  }
  if(this.queue.size() == 0) {
    notifyAll();
  }
  this.queue.add(item);
}

Why is the while loop necessary, and can the while be replaced by if (this.queue.size() == this.limit)

It seems the method enqueue is synchronized so only 1 thread at a time can be executing in the method body and make the call to wait(). Once the thread is notified, can't it just continue onward without checking the this.queue.size() == this.limit condition again?

2
  • Thanks. Follow up question: why does enqueue call notifyAll() before the item is added? Wouldn't this potentially cause threads waiting to dequeue to check an empty queue? Would it be better to first add the item and then notifyAll? like so: queue.add(item); if (queue.size()==1){notifyAll();} Commented Mar 26, 2012 at 8:43
  • IMHO, the order off the add(item) and notifyAll() doesn't matter as the method enqueue is synchronized. So both the add(item) and notifyAll() calls must complete before another thread can execute. Commented Mar 26, 2012 at 9:06

2 Answers 2

5

The documentation on Object.wait() explains it best:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }
Sign up to request clarification or add additional context in comments.

Comments

4

No. You need the while because there might be multiple threads waiting for the space in the queue to open up, and the notifyAll() calls will wake all of them up.

The wait() method actually releases the synchronisation monitor so that other threads can make progress. If it didn't, then any thread trying to remove stuff from the queue would also get stuck waiting to enter a synchronised block in the get() method (for example).

Only one of the waiting threads will see a partially empty queue.

Actually, none of them might; the threads might have been woken up with notifyAll for some completely unrelated reason.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.