Difference between wait() and notify() in Java
In this tutorial, we are going to learn about the difference between wait() and notify() in Java.
wait():
wait() is a method in Java that is used for synchronization and inter-thread communication. It is part of the Java Object class and is often used in multi-threaded programs to allow threads to coordinate their actions by voluntarily giving up control of a monitor (object's intrinsic lock) and waiting for another thread to notify them when it's safe to proceed.
Syntax:
synchronized (object) { while (condition) { object.wait(); } }
Usage within Synchronized Blocks or Methods:
To use wait(), you typically need to be within a synchronized block or synchronized method. This is because wait() must be called on an object for which the current thread already holds the lock. If it's not called within a synchronized context, it will result in a java.lang.IllegalMonitorStateException.
Release of the Monitor:
When a thread invokes wait() on an object, it temporarily releases the lock on that object, allowing other threads to enter synchronized blocks or methods on that object.
Putting a Thread to Sleep:
The wait() method also puts the current thread to sleep and waits until another thread calls notify() or notifyAll() on the same object.
notify():
notify() is a method in Java that is used for synchronization and inter-thread communication. It is part of the Java Object class and is often used in multi-threaded programs to notify a waiting thread that it can proceed with its execution.
Syntax:
synchronized (object) { // Perform some task and notify waiting threads if required object.notify(); // or object.notifyAll() to wake up all waiting threads }
Usage within Synchronized Blocks or Methods:
To use notify(), you typically need to be within a synchronized block or synchronized method. This is because notify() must be called on an object for which the current thread already holds the lock. If it's not called within a synchronized context, it will result in a java.lang.IllegalMonitorStateException.
Signaling Threads:
The primary purpose of notify() is to signal one of the threads that are currently waiting on the same object. When notify() is called, it wakes up one of the waiting threads (if any). Which specific thread gets awakened is not deterministic and depends on the JVM's scheduling.
No Guarantee of Specific Thread Wakeup:
It's important to note that notify() doesn't guarantee which waiting thread will be awakened. If you need to ensure that all waiting threads are awakened, you can use the notifyAll() method.
Differences
Aspect | Wait() | Notify() |
Purpose | Used by a thread to voluntarily give up its hold on a monitor and wait for another thread to notify it when it can proceed. | Used to wake up one of the threads that are currently waiting on the same monitor. |
Usage | Within a synchronized block or synchronized method. It must be called on an object for which the current thread already holds the lock. | Within a synchronized block or synchronized method. It must be called on an object for which the current thread already holds the lock. |
Release of Lock | Releases the lock on the object, allowing other threads to enter synchronized blocks or methods on that object. | Does not release the lock. It only wakes up one of the waiting threads, allowing it to continue execution. |
Thread Sleep | The wait() method also puts the current thread to sleep and waits until another thread calls notify() or notifyAll() on the same object. | The notify() method does not have this aspect and is not applicable. |
Exception Handling | Must be enclosed in a try-catch block to handle InterruptedException because a thread can be interrupted while waiting. | The notify() method does not have this aspect and is not applicable. |
Signaling | Awaits notification from another thread to proceed. | Signals one of the waiting threads to wake up and continue execution. |
Specific Thread Wakeup | The wait() method does not have this aspect and is not applicable. | Does not guarantee which specific waiting thread will be awakened. |
Multiple Threads | Multiple threads can wait on the same object. | One thread can use notify() to wake up one of the waiting threads. |
Spurious Wakeups | Threads may wake up without a corresponding notify() or notifyAll() call (spurious wakeups). Should be used within a loop to check the condition. | The notify() method does not have this aspect and is not applicable. |
Blocking Behavior | wait() blocks the current thread, suspending its execution until it receives a notification from another thread or until a specified timeout period elapses. | notify() does not block the current thread; it simply sends a signal to one of the waiting threads to wake up and compete for the lock. |
Number of Threads | Multiple threads can call wait() on the same object and wait for different conditions, as each thread can have its own condition check. | notify() typically wakes up only one of the waiting threads, which may not be the one expecting a specific condition change. |
Signaling Specificity | wait() is often used when a thread is waiting for a particular condition to change. It can check the condition in a loop upon waking to avoid spurious wakeups. | notify() is a general notification and doesn't provide a mechanism for specifying which particular waiting thread should be awakened. |
Usage in Producer-Consumer | Typically used in the consumer thread to wait for the producer to produce data, and then the producer calls notify() to wake up the consumer. | Typically used in the producer thread to notify the consumer that new data is available for consumption. |
Use Cases | Commonly used for implementing thread-safe patterns like producer-consumer, bounded buffers, and other scenarios where threads need to synchronize their actions. | Commonly used in scenarios where a change in a shared condition or resource needs to be communicated to waiting threads. |
These differences highlight the specific roles and behaviors of wait() and notify() in facilitating thread synchronization and communication in Java. While wait() allows threads to wait for specific conditions, notify() is used to signal waiting threads, although it doesn't specify which thread should be awakened.
Filename: WaitAndNotify.java
class SharedResource { private int data; private boolean dataReady = false; public synchronized void produceData(int value) { while (dataReady) { try { wait(); // Wait until data is consumed. } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Producer interrupted."); return; } } data = value; dataReady = true; System.out.println("Producer produced: " + data); notify(); // Notify the consumer that data is ready. } public synchronized void consumeData() { while (!dataReady) { try { wait(); // Wait until data is produced. } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Consumer interrupted."); return; } } System.out.println("Consumer consumed: " + data); dataReady = false; notify(); // Notify the producer that data has been consumed. } } public class WaitAndNotify { public static void main(String[] args) { SharedResource sharedResource = new SharedResource(); Thread producerThread = new Thread(() -> { for (int i = 1; i <= 5; i++) { sharedResource.produceData(i); } }); Thread consumerThread = new Thread(() -> { for (int i = 1; i <= 5; i++) { sharedResource.consumeData(); } }); producerThread.start(); consumerThread.start(); try { producerThread.join(); consumerThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Main thread interrupted."); } } }
Output:
Producer produced: 1 Consumer consumed: 1 Producer produced: 2 Consumer consumed: 2 Producer produced: 3 Consumer consumed: 3 Producer produced: 4 Consumer consumed: 4 Producer produced: 5 Consumer consumed: 5
Both produceData and consumeData methods use wait() to wait for the data to be available or consumed, respectively.
When data is produced or consumed, the corresponding thread calls notify() to signal the other thread to wake up and continue its execution.
The output will show how the producer and consumer take turns producing and consuming data in a synchronized manner.