Difference Between notify() and notifyAll() in Java
Introduction to wait(), notify(), notifyALL() methods in Java
The `wait()`, `notify()`, and `notifyAll()` methods are used to synchronize threads in Java. These methods allow threads to communicate with each other and coordinate their activities.
The `wait()` method causes the current thread to wait until another thread notifies it or interrupts it. The `notify()` method wakes up one thread that is waiting on the same object. The `notifyAll()` method wakes up all threads that are waiting on the same object.
These methods are typically used to implement producer-consumer patterns, where one thread produces data and another thread consumes it. The producer thread can use the `wait()` method to wait until there is space to produce more data. The consumer thread can use the `notify()` or `notifyAll()` methods to wake up the producer thread when there is more data to consume.
Here is an example of a simple producer-consumer pattern using the `wait()`, `notify()`, and `notifyAll()` methods:
public class ProducerConsumer {
private Object lock = new Object();
private Queue queue = new LinkedList<>();
public void produce() {
synchronized (lock) {
while (queue.size() == 10) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(1);
lock.notifyAll();
}
}
public void consume() {
synchronized (lock) {
while (queue.isEmpty()) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer item = queue.poll();
lock.notifyAll();
}
}
}
In this example, the `produce()` method produces an item and adds it to the queue. If the queue is full, the `produce()` method waits for the consumer thread to empty the queue. The `consume()` method removes an item from the queue and consumes it. If the queue is empty, the `consume()` method waits for the producer thread to produce more items.
The `wait()`, `notify()`, and `notifyAll()` methods are powerful tools for synchronizing threads in Java. However, it is important to use them carefully to avoid race conditions and other errors.
Here are some tips for using the `wait()`, `notify()`, and `notifyAll()` methods effectively:
- Only call `wait()` from within a synchronized block.
- Call `notify()` or `notifyAll()` to wake up waiting threads after you have modified the shared data.
- Be careful not to create deadlocks. A deadlock occurs when two or more threads are waiting for each other to finish executing before they can continue. To avoid deadlocks, follow the rules of lock acquisition and release.
The `wait()`, `notify()`, and `notifyAll()` methods can be used to implement a variety of different patterns and algorithms in Java. By understanding the basics of these methods, you can write more efficient and reliable concurrent Java programs.
Here are some additional examples of how the `wait()`, `notify()`, and `notifyAll()` methods can be used:
- To implement a thread pool, where a group of threads are used to execute tasks concurrently.
- To implement a barrier, where a group of threads must all wait until a certain condition is met before proceeding.
- To implement a semaphore, which is a resource that can only be used by a limited number of threads at a time.
The `wait()`, `notify()`, and `notifyAll()` methods are essential tools for writing concurrent Java programs. By understanding the basics of these methods, you can write more efficient and reliable code.
Exercises
Code for demonstrating the use of wait and notify method in Threads
package sampleproject;
import java.util.*;
import java.io.*;
public class democlass{
public static void main(String[] args) throws InterruptedException {
account satish = new account(2000);
Thread thr1 = new Thread(new Runnable() {
@Override
public void run() {
satish.withdraw(10000);
}
});
Thread thr2 = new Thread(new Runnable() {
@Override
public void run() {
satish.deposit_amount(20000);
}
});
thr1.start();
thr2.start();
thr1.join();
thr2.join();
System.out.println(satish.balance);
}
}
class account
{
public int balance;
public account(int amount) {
this.balance=amount;
}
public synchronized void withdraw(int withdraw_amount){
System.out.println("trying withdrawal");
if(withdraw_amount>this.balance)
{
System.out.println("entering wait state");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("reducing balance");
this.balance=this.balance-withdraw_amount;
}
public synchronized void deposit_amount(int deposit) {
System.out.println("depositing amount");
this.balance=this.balance+deposit;
notify();
}
}
Code for demonstrating the use of wait and notifyAll method in Threads
package sampleproject;
import java.util.*;
import java.io.*;
public class democlass{
public static void main(String[] args) throws InterruptedException {
account satish = new account(2000);
Thread thr1 = new Thread(new Runnable() {
@Override
public void run() {
satish.withdraw(10000);
}
});
Thread thr2 = new Thread(new Runnable() {
@Override
public void run() {
satish.withdraw(20000);
}
});
Thread thr3 = new Thread(new Runnable() {
@Override
public void run() {
satish.deposit_amount(20000);
}
});
thr1.start();
thr2.start();
thr3.start();
thr1.join();
thr2.join();
thr3.join();
System.out.println(satish.balance);
}
}
class account
{
public int balance;
public account(int amount) {
this.balance=amount;
}
public synchronized void withdraw(int withdraw_amount){
System.out.println("trying withdrawal");
if(withdraw_amount>this.balance)
{
System.out.println("entering wait state");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("reducing balance");
this.balance=this.balance-withdraw_amount;
}
public synchronized void deposit_amount(int deposit) {
System.out.println("depositing amount");
this.balance=this.balance+deposit;
notifyAll();
}
}