Inter Thread Communication using wait(), notify() and notifyAll() in Java

We will discuss here what are the purpose of wait(), notify() and notifyAll() methods in Java. These methods are used in inter-thread communication. Each thread in Java has its own separate path of execution, so when you need to establish communication among threads then you need to use these methods.

Let’s say a thread wants to tell another thread that there is something in the shared object for your consumption, or in other word, another thread is waiting for something in the shared object. Then notify() or notifyAll() methods notify the waiting thread or threads to wake up to the shared object or resources for which the thread or threads were waiting.

Without wait(), notify() or notifyAll() methods, the waiting thread(s) had to check shared object very often for the item even if the thread might not have required.

The classical problem is solved in inter-thread communication is producer consumer problem. Producer produces an item and put into a shared bucket and consumer consumes item from the shared bucket.

When producer produces item and put into bucket then state of the shared object gets changed and notify() or notifyAll() method is invoked to notify the consumer(s) and consumer(s) pick(s) the item.

Remember wait() and notify() or notifyAll() methods must be called from synchronized context and use loop to check the condition instead of if block.

If you use if block for checking condition and if consumer thread wakes up due to false alarm and tries to get an item from the queue without further checking whether queue is empty or not may result inconsistency if the queue is empty. So there is no second chance to check the condition further.

There is a difference between notify() and notifyAll() methods. When you know there is one to one communication between two threads, then you can use notify() method but if there are multiple threads communicating among themselves then you can use notifyAll() method.

In the below example we will see how wait(), notify() and notifyAll() methods work.

We will solve a classical producer consumer problem, where producer will produce items and consumer will consume item.

You may also like to read how to solve the producer consumer problem using BlockingQueue.

Now we will look into producer and consumer classes in the below example.

We will first check with wait() and notify() methods when two threads are communicating between them.

Producer

package com.roytuts.java.inter.thread.communication.wait.notify.notifyall;

import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Producer<E> implements Runnable {

	private static final Logger LOGGER = Logger.getLogger(Producer.class.getName());

	private E e;
	private final Queue<E> queue;

	public Producer(E e, Queue<E> queue) {
		this.e = e;
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (queue) {
				while (!queue.isEmpty()) {
					try {
						LOGGER.log(Level.INFO, "[" + Thread.currentThread().getName() + "]: Queue is full. Waiting...");
						queue.wait();
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
				LOGGER.log(Level.INFO, "[" + Thread.currentThread().getName() + "]: Producing..." + e);
				queue.add(e);
				queue.notify();
			}
		}
	}

}

Consumer

package com.roytuts.java.inter.thread.communication.wait.notify.notifyall;

import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Consumer<E> implements Runnable {

	private static final Logger LOGGER = Logger.getLogger(Consumer.class.getName());

	private final Queue<E> queue;

	public Consumer(Queue<E> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (queue) {
				while (queue.isEmpty()) {
					try {
						LOGGER.log(Level.INFO,
								"[" + Thread.currentThread().getName() + "]: Queue is empty. Waiting...");
						queue.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				E e = queue.poll();
				LOGGER.log(Level.INFO, "[" + Thread.currentThread().getName() + "]: Consuming..." + e);
				queue.notify();
			}
		}
	}

}

Testing

package com.roytuts.java.inter.thread.communication.wait.notify.notifyall.app;

import java.util.LinkedList;
import java.util.Queue;

import com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Consumer;
import com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Producer;
import com.roytuts.java.inter.thread.communication.wait.notify.notifyall.enums.Currency;
import com.roytuts.java.inter.thread.communication.wait.notify.notifyall.model.Money;

public class JavaWaitNotifyNotifyAllApp {

	public static void main(String[] args) {
		Money money = new Money(6454.00, Currency.RUPEE);

		Queue<Money> queue = new LinkedList<Money>();

		Producer<Money> producer = new Producer<Money>(money, queue);

		Consumer<Money> consumer = new Consumer<Money>(queue);

		new Thread(producer, "Producer").start();
		new Thread(consumer, "Consumer").start();
	}

}

Output

You will see below output keep going…

INFO: [Producer]: Producing...Money [amount=6454.0, currency=RUPEE]
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Producer run
INFO: [Producer]: Queue is full. Waiting...
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Consumer run
INFO: [Consumer]: Consuming...Money [amount=6454.0, currency=RUPEE]
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Consumer run
INFO: [Consumer]: Queue is empty. Waiting...
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Producer run
INFO: [Producer]: Producing...Money [amount=6454.0, currency=RUPEE]
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Producer run
INFO: [Producer]: Queue is full. Waiting...
com.roytuts.java.inter.thread.communication.wait.notify.notifyall.Consumer run
INFO: [Consumer]: Consuming...Money [amount=6454.0, currency=RUPEE]
...

We will see with wait() and notifyAll() methods for more than two threads communicating among themselves.

You need to just change the line queue.notify(); by queue.notifyAll(); in both Producer and Consumer classes.

Replace the main method inside JavaWaitNotifyNotifyAllApp class by the following code snippets:

public static void main(String[] args) {
	Money money = new Money(6454.00, Currency.RUPEE);

	Queue<Money> queue = new LinkedList<Money>();

	Producer<Money> producer = new Producer<Money>(money, queue);

	Consumer<Money> consumer1 = new Consumer<Money>(queue);
	Consumer<Money> consumer2 = new Consumer<Money>(queue);

	new Thread(producer, "Producer").start();
	new Thread(consumer1, "Consumer1").start();
	new Thread(consumer2, "Consumer2").start();
}

Now again you can execute the main class and check the output.

Source Code

Download

Thanks for reading.

Leave a Comment