wait() and notify() Simple example

๐Ÿ”„ Understanding wait() and notify() in Java (with Example)

In multithreaded programming, thread coordination is often needed when multiple threads work on the same shared resource.
In Java, this coordination is achieved using the wait() and notify() methods from the Object class.


⚙️ What Are wait() and notify()?

๐Ÿ•’ wait()

  • Causes the current thread to pause its execution and release the lock on the object it’s holding.

  • The thread stays in the waiting state until another thread calls notify() or notifyAll() on the same object.

  • Must be called inside a synchronized block.

๐Ÿš€ notify()

  • Wakes up one thread that is waiting on the same object’s monitor.

  • The awakened thread will compete to reacquire the lock and continue execution.

๐Ÿ’ก Important:
Both wait() and notify() must be used inside synchronized blocks or methods, otherwise a java.lang.IllegalMonitorStateException will be thrown.


๐Ÿงฉ Example — Coordinating Two Threads Using wait() and notify()

In the below example:

  • Two threads share the same ArrayList resource.

  • removeRecord thread waits until there’s data to remove.

  • addRecord thread adds a record and then notifies the waiting thread to continue.


๐Ÿ’ป Java Code

package com.vinod.test; import java.util.ArrayList; import java.util.List; /** * Demonstrates wait() and notify() for thread communication. * * In this example: * - One thread adds a student record. * - Another thread waits until the record is added, then removes it. * * @author vinod */ public class ConcurrentTest { public static void main(String[] args) { final List<String> students = new ArrayList<>(); // Thread 1: Adds a record after some delay Thread addRecord = new Thread(() -> { System.out.println("AddRecord thread started..."); try { Thread.sleep(10000); // simulate delay before adding } catch (InterruptedException e) { e.printStackTrace(); } synchronized (students) { System.out.println("Thread 1 locked the list and adding student details..."); students.add("Pretech"); System.out.println("Student details added by Thread 1: " + students); // Notify waiting thread students.notify(); System.out.println("Thread 1 sent notification to waiting thread."); } }); // Thread 2: Waits until a record is available to remove Thread removeRecord = new Thread(() -> { System.out.println("RemoveRecord thread started..."); synchronized (students) { System.out.println("Thread 2 locked the list..."); if (students.isEmpty()) { try { System.out.println("List is empty — Thread 2 waiting for notification..."); students.wait(); // releases lock and waits } catch (InterruptedException e) { e.printStackTrace(); } } // Remove record after being notified if (!students.isEmpty()) { System.out.println("Removing item: " + students.get(0)); students.remove(0); } System.out.println("Student list after removal by Thread 2: " + students); } }); addRecord.start(); removeRecord.start(); } }

๐Ÿงพ Example Output

RemoveRecord thread started... Thread 2 locked the list... List is emptyThread 2 waiting for notification... AddRecord thread started... Thread 1 locked the list and adding student details... Student details added by Thread 1: [Pretech] Thread 1 sent notification to waiting thread. Removing item: Pretech Student list after removal by Thread 2: []

๐Ÿง  Step-by-Step Explanation

Step 1: removeRecord thread starts first and locks the students list. Step 2: It finds the list empty → calls wait() → releases the lock → waits. Step 3: addRecord thread starts, acquires the lock, and adds a student. Step 4: After adding, it calls notify() → signals the waiting thread. Step 5: removeRecord thread wakes up, reacquires the lock, removes the record. Step 6: Both threads complete their tasks safely without race conditions.

๐Ÿงฉ Text-Based Visualization

Thread 2: wait() ─────────┐ │ Thread 1: add + notify() ─┘ wakes Thread 2

At any given time:

  • Only one thread holds the lock on the shared resource (students).

  • The wait() call temporarily releases that lock.

  • The notify() call signals another waiting thread to resume once the lock becomes available.


๐Ÿงฑ Key Points to Remember

MethodDescription
wait()Pauses the current thread and releases the lock
notify()Wakes up one waiting thread on the same object
notifyAll()Wakes up all threads waiting on the same object
Must use inside synchronizedRequired for thread safety and correct monitor behavior
Common use caseProducer–Consumer and resource coordination patterns

⚠️ Common Mistakes to Avoid

  1. ❌ Calling wait() or notify() outside a synchronized block → throws IllegalMonitorStateException.

  2. ❌ Forgetting to handle InterruptedException.

  3. ❌ Not checking condition again after wait() (always recheck the condition in a loop in real applications).

  4. ❌ Using shared resource without proper synchronization → causes data inconsistency.


✅ Best Practice

In real-world scenarios, always use a while loop around wait() to handle spurious wake-ups:

while (students.isEmpty()) { students.wait(); }

This ensures that the thread only proceeds when the condition is actually met.


No comments:

Post a Comment

Model Context Protocol (MCP) — Complete Guide for Backend Engineers

  Model Context Protocol (MCP) — Complete Guide for Backend Engineers Build Tools, Resources, and AI-Driven Services Using LangChain Moder...

Featured Posts