When using Java Thread to create multi-threaded programs, sometimes it is necessary to wait for other threads to finish execution before starting another set of threads. The main purpose of wait()
and notify()
is to achieve communication and synchronization between threads, commonly used in scenarios involving shared resources to ensure thread-safe access to those resources.
wait()
:
Purpose: Puts the current thread into a waiting state (suspending its execution). Additionally, wait()
causes the current thread to release the lock it holds. The thread remains in a waiting state until another thread invokes the notify()
or notifyAll()
method on the same object, waking up the waiting thread.
Note: The wait()
method allows the current thread to wait until it receives a notification or is interrupted. It should be called within a synchronized method or block. If the thread does not hold the appropriate lock, it will throw an Exception
.
notify()
:
Purpose: Should be called within a synchronized method or block as well. The notify()
method is used to notify other threads that are possibly waiting for the lock on the same object, allowing one of them to regain the lock and continue its execution. If multiple threads are waiting, only one of them will be notified. To notify all waiting threads, notifyAll()
can be used instead.
Please note that both wait()
and notify()
methods should be used within synchronized methods or blocks to ensure proper thread synchronization. The calling thread should hold the lock on the object before calling these methods to avoid any exceptions or unexpected behavior.
import javax.swing.text.Document;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Main {
public static void main(String[] args) throws Exception {
SharedResource sharedResource = new SharedResource();
Runnable produceTask = () -> {
for (int i = 1; i <= 10; i++) {
sharedResource.produceData(i);
}
};
Runnable consumeTask = () -> {
for (int i = 1; i <= 10; i++) {
sharedResource.consumeData();
}
};
Thread producerThread = new Thread(produceTask);
Thread consumerThread = new Thread(consumeTask);
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class SharedResource{
private Queue<Integer> queue = new LinkedList<>();
private int maxSize = 5;
public synchronized void produceData(int value){
while(queue.size() >= maxSize){
try {
wait();
// The producer thread enters a waiting state on its own
// it enters a waiting state and releases the lock
// on the produceData method, allowing other threads
// to enter the synchronized block of the produceData method
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
queue.add(value);
System.out.println("Produced: " + value);
notify();
}
public synchronized void consumeData() {
while (queue.isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int data = queue.poll();
System.out.println("Consumed: " + data);
notify();
}
}
}