← Back to Advanced Java Course | Chapter 2: Multithreading | Lesson 5 of 8

Java wait & notify

wait and notify let threads signal each other, like one person waiting for a friend's shout of 'the food is ready'. One thread pauses until another says it can go on.
Syntax
java
synchronized (lockObject) {
    while (!condition) {
        lockObject.wait();
    }
    lockObject.notify();  // or notifyAll()
}

Inter-Thread Communication

Inter-thread communication lets synchronized threads coordinate their work and exchange signals using three methods inherited from the Object class: wait(), notify(), and notifyAll(). These let threads pause until conditions elsewhere in the program change, rather than wastefully polling in a loop.

Example: Inter-Thread Communication

java
// Define the class Main
public class Main {
	// Program entry point: the JVM starts running here
	public static void main(String[] args) throws InterruptedException {
		// Create a new Object object and store it in monitor
		Object monitor = new Object();
		// synchronized lets only one thread run this code at a time
		synchronized (monitor) {
			// Print a line to the console
			System.out.println("wait()/notify()/notifyAll() coordinate threads via this monitor");
		}
	}
}

The wait() Method

Calling wait() inside a synchronized block immediately pauses the calling thread and, crucially, releases the monitor lock it was holding, letting other threads acquire that same lock and make progress. The waiting thread stays paused until some other thread calls notify() or notifyAll() on that same object.

Example: The wait() Method

java
public class Main {
	public static void main(String[] args) throws InterruptedException {
		final Object lock = new Object();
		Thread waiter = new Thread(() -> {
			synchronized (lock) {
				try {
					System.out.println("Waiting...");
					lock.wait(200); // releases the lock while paused
					System.out.println("Resumed");
				} catch (InterruptedException e) {}
			}
		});
		waiter.start();
		waiter.join();
	}
}

The notify() Method

The notify() method wakes up a single, arbitrarily chosen thread that's currently waiting on the object's monitor lock. It must be called from inside a synchronized block on that same object, and if multiple threads are waiting, there's no guarantee which one gets picked.

Example: The notify() Method

java
// Define the class Main
public class Main {
	// Program entry point: the JVM starts running here
	public static void main(String[] args) throws InterruptedException {
		// Create a new Object object and store it in lock
		final Object lock = new Object();
		// Create a new Thread object and store it in waiter
		Thread waiter = new Thread(() -> {
			// synchronized lets only one thread run this code at a time
			synchronized (lock) {
				// Try code that might throw an exception
				try { lock.wait(); } catch (InterruptedException e) {}
				// Print a line to the console
				System.out.println("Woken by notify()");
			}
		});
		// Start the thread; it runs in parallel with this code
		waiter.start();
		Thread.sleep(100);
		synchronized (lock) { lock.notify(); }
		waiter.join();
	}
}

The notifyAll() Method

The notifyAll() method wakes up every thread currently waiting on the object's monitor, rather than just one. This is generally the safer choice over notify() when multiple threads might be waiting for different conditions, since notify() alone could accidentally wake the wrong one.

Example: The notifyAll() Method

java
public class Main {
	public static void main(String[] args) throws InterruptedException {
		final Object lock = new Object();
		Runnable waitTask = () -> {
			synchronized (lock) {
				try { lock.wait(); } catch (InterruptedException e) {}
				System.out.println(Thread.currentThread().getName() + " woken");
			}
		};
		Thread t1 = new Thread(waitTask), t2 = new Thread(waitTask);
		t1.start(); t2.start();
		Thread.sleep(100);
		synchronized (lock) { lock.notifyAll(); } // wakes both, not just one
		t1.join(); t2.join();
	}
}

Producer-Consumer Simulation

The classic producer-consumer pattern uses wait() and notify() to coordinate a shared, bounded buffer: the producer calls wait() when the buffer is full, and the consumer calls wait() when it's empty, with each side calling notify() after changing the buffer's state to wake the other up.

Example: Producer-Consumer Simulation

java
// Import java.util.LinkedList so it can be used by its short name
import java.util.LinkedList;
// Define the class Main
public class Main {
	// Create a new LinkedList object and store it in buffer
	static final LinkedList<Integer> buffer = new LinkedList<>();
	static final int CAPACITY = 1;
	// Program entry point: the JVM starts running here
	public static void main(String[] args) throws InterruptedException {
		// Create a new Thread object and store it in producer
		Thread producer = new Thread(() -> {
			// synchronized lets only one thread run this code at a time
			synchronized (buffer) {
				while (buffer.size() == CAPACITY) { try { buffer.wait(); } catch (InterruptedException e) {} }
				buffer.add(42);
				// Print a line to the console
				System.out.println("Produced 42");
				buffer.notify();
			}
		});
		Thread consumer = new Thread(() -> {
			// synchronized lets only one thread run this code at a time
			synchronized (buffer) {
				while (buffer.isEmpty()) { try { buffer.wait(); } catch (InterruptedException e) {} }
				System.out.println("Consumed " + buffer.poll());
			}
		});
		producer.start(); producer.join();
		consumer.start(); consumer.join();
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Calling wait() or notify() outside a synchronized block on the same object, which throws an IllegalMonitorStateException.
  2. Checking the condition with if instead of a while loop before wait(), so a spurious wakeup or another thread can leave the condition false when the thread continues.
  3. Calling notify() before the other thread has called wait(), so the signal is lost and the waiting thread sleeps forever.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.