The notifyAll() method

An alternative to notify() is notifyAll(). As the name implies, this method wakes up all threads that are waiting on the given object. So which is appropriate where?

The notify() method is generally used for resource pools, where there are an arbitrary number of "consumers" or "workers" that take resources, but when a resource is added to the pool, only one of the waiting consumers or workers can deal with it. The notifyAll() method is actually used in most other cases. Strictly, it is required to notify waiters of a condition that could allow multiple waiters to proceed. But this is often difficult to know. So as a general rule, if you have no particular logic for using notify(), then you should probably use notifyAll(), because it is often difficult to know exactly what threads will be waiting on a particular object and why. For example, imagine we have a fixed-size buffer object. Threads can add objects to the buffer, but must wait if the buffer is full. The class also has a clear() method to empty the buffer:

public class Buffer {
  private List buffer = new ArrayList();

  public void addItem(V obj) {
    synchronized (buffer) {
      while (buffer.size() >= maxSize) {
        buffer.wait();
      }
      buffer.add(obj);
    }
  }

  public void clear() {
    synchronized (buffer) {
      buffer.clear();
      buffer.notifyAll();
    }
  }
}

Now, it's crucial that the clear() method calls notifyAll() because it can't tell how many threads are waiting on the buffer, and it performs an action that can potentially allow various of those threads to proceed.

Generally, if you accidentally call notifyAll() where only notify() is necessary, this should not cause your program logic to fail: at worst it will cause some unnecessary context switches as a bunch of threads are in turn woken up, only to find that the condition they were waiting for has not yet been met, and that they must immediately wait again. But the converse is not true, as in the Buffer.clear() method above: here, notifyAll() is necessary because there could be several threads waiting, and clear() is the only method that does something to allow them to proceed.

Of course, the semantics of the synchronized lock still apply with notifyAll(). That is to say, each of the awoken threads will, in turn, acquire the lock and proceed. The next awoken thread 'in the queue' will proceed only after the previous one has released the lock, either by exiting the synchronized block or by re-entering the wait() method.


If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.