Java
notify
notifyAll
multithreading
concurrency

Java notify vs. notifyAll all over again

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Java provides powerful tools for multi-threaded programming, allowing developers to manage the execution of threads in a well-ordered and efficient manner. Among these tools are the methods notify() and notifyAll(), which belong to the java.lang.Object class and are crucial for effective thread coordination. This article dives deep into these methods, exploring their differences, use cases, and technical underpinnings.

Understanding notify() and notifyAll()

When a thread in Java needs to wait for some condition to hold true before it can proceed, it often uses the wait() method within a synchronized block. The notify() and notifyAll() methods are used to wake up threads that are waiting on a particular object's monitor.

notify()

The notify() method wakes a single thread that is waiting on the object's monitor. If multiple threads are waiting, the selection of the thread to be awakened is arbitrary and depends on the implementation. Crucially, notify() does not release the lock on the object; the awakened thread cannot proceed until the thread that invoked notify() has exited the synchronized block.

Example Usage of notify()
java
1public class NotifyExample {
2    private static final Object lock = new Object();
3    
4    static class WaitingThread extends Thread {
5        @Override
6        public void run() {
7            synchronized (lock) {
8                try {
9                    System.out.println("Thread is waiting...");
10                    lock.wait();
11                    System.out.println("Thread is resumed.");
12                } catch (InterruptedException e) {
13                    Thread.currentThread().interrupt();
14                }
15            }
16        }
17    }
18
19    public static void main(String[] args) throws InterruptedException {
20        WaitingThread thread = new WaitingThread();
21        thread.start();
22
23        Thread.sleep(1000); // Sleep to ensure that the other thread starts first
24
25        synchronized (lock) {
26            System.out.println("Notifying a thread...");
27            lock.notify();
28        }
29    }
30}

notifyAll()

On the other hand, notifyAll() wakes up all the threads that are waiting on the object's monitor. Once again, the awakened threads will need to contend for the lock on the object, and only one can proceed at a time.

Example Usage of notifyAll()
java
1public class NotifyAllExample {
2    private static final Object lock = new Object();
3    
4    static class WaitingThread extends Thread {
5        @Override
6        public void run() {
7            synchronized (lock) {
8                try {
9                    System.out.println(Thread.currentThread().getName() + " is waiting...");
10                    lock.wait();
11                    System.out.println(Thread.currentThread().getName() + " is resumed.");
12                } catch (InterruptedException e) {
13                    Thread.currentThread().interrupt();
14                }
15            }
16        }
17    }
18
19    public static void main(String[] args) throws InterruptedException {
20        for (int i = 0; i < 3; i++) {
21            new WaitingThread().start();
22        }
23
24        Thread.sleep(1000); // Ensure all threads have started and are waiting
25
26        synchronized (lock) {
27            System.out.println("Notifying all threads...");
28            lock.notifyAll();
29        }
30    }
31}

Key Differences between notify() and notifyAll()

Both methods serve the purpose of waking up thread(s) that are waiting on an object's monitor, but their use cases differ significantly.

Featurenotify()notifyAll()
Number of threads wokenOne thread, choice is arbitrary and implementation-dependentAll threads waiting on the monitor
Resource EfficiencyMore efficient for single-thread notifications, less overheadMore overhead but ensures all waiting threads are given a chance to proceed
Use CasesUse when only one thread needs to be awakened, e.g., producer-consumer modelUse when multiple threads should react to state changes, e.g., when system state affects multiple threads

Usage Considerations

  • Performance: If only one thread is needed to process a task, using notify() can be more resource-efficient, as it involves less of a context-switching overhead.
  • Complexity: In a multi-threading environment where the state changes affect multiple threads or operations, using notifyAll() ensures that all potential actions are considered. It is a safer option in complex systems where you cannot predict which thread should ideally be awakened.
  • Determinacy: Using notify() can introduce non-deterministic behavior since which thread will be chosen for awakening is not guaranteed. This can become a source of bugs if not managed carefully.

Additional Tips

  • Always Call within a Synchronized Context: Both notify() and notifyAll() must be called from within a synchronized block or method; otherwise, IllegalMonitorStateException is thrown.
  • Avoid Missed Notifications: Ensure threads wait inside a loop that checks the condition it is waiting for. This prevents missed signals and spurious wake-ups. The recommended pattern is:
java
1  synchronized(lock) {
2      while (!condition) {
3          lock.wait();
4      }
5      // Proceed when condition holds true.
6  }

Conclusion

Choosing between notify() and notifyAll() largely depends on the system requirements and the concurrency aspects of the application. notify() serves well in specific, straightforward scenarios, whereas notifyAll() provides a blanket approach suitable for more intricate systems. Understanding these differences and their implications can help in crafting robust, efficient multi-threaded Java applications. Always consider the larger context and specific needs when deciding which method to employ, keeping future scalability and system complexity in mind.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.