Saturday 13 May 2017

wait(), notify() and notifyAll() in Java



Hello Guys !!! Hope You all are doing well.
Today I am going to discuss one of the most import concept of java Thread.
wait(), notify() and notifyAll() methods are quite obvious because they are the one of the three methods of total 9 methods from java.lang.Object. I am sharing here some practical tips and points about wait(), notify() and notifyAll() in Java and its uses in java program.

1. wait, notify and notifyAll are related to threads they are not defined in java.lang.Thread class, instead they are defined in the Object class. why? as per my understanding there are three reason :-


(A) Wait and notify is not just normal methods or synchronization utility,They are communication mechanism between two threads in Java. So An Object class is correct place to make them available for every object.

(B) Locks are made available as per Object basis, that's why wait and notify is declared in Object class rather then Thread class.

(C) As per Java design, the thread can not be specified, it is always the current thread running the code. However, we can specify the monitor (object). So it is a good design, if we could make any other thread to wait on a desired monitor.

2. We must call the wait(), notify() and notifyAll() methods from a synchronized context in Java i.e. inside synchronized method or a synchronized block.
why is this restriction??? Explanation:-

(A) The thread must hold the lock on the object it is going to call the wait() or notify() method and that is acquired when it enter into a synchronized context.
If you call it without holding a lock then they will throw IllegalMonitorStateException in Java.

(B) To avoid any potential race condition between wait() and notify() method.

3. The best approach to call wait() method from inside a loop, don't call with an if block because a thread can occasionally or irregularly awake from the wait state without being notified by another party. So in that case, this could result in a bug.
example :-

synchronized (sharedObject) {

while (condition) {

sharedObject.wait();

}

// do something

}


4. When a thread calls the wait() method in Java, it goes to the wait state by releasing the lock, which is later acquired by the other thread who can notify this thread. Here is a nice diagram of how state transition of a thread happens in Java:
Inline image 1

5. A thread waiting due to wait() method call, then it can wake up either by calling notify() or notifyAll() method on the same object or due to interruption.

6. Difference between notify() and notifyAll() is that in case of notify() only one of the waiting thread gets a notification but in case of notifyAll() all thread get notification.

So far, we learned few basic things for wait, notify and notifyAll (which you probably already knew). Let’s write a small java program.

In this program, we will solve producer consumer problem using wait() and notify() methods.
To keep program simple, we will involve only one producer and one consumer thread.
Other features of the program are :

  1. Producer thread produce a new resource in every 1 second and put it in ‘taskQueue’.
  2. Consumer thread takes 1 seconds to process consumed resource from ‘taskQueue’.
  3. Max capacity of taskQueue is 7 i.e. maximum 7 resources can exist inside ‘taskQueue’ at any given time.
  4. Both threads run infinitely.

You can download source code from my github account

ProducerThread.java file add task in TaskQueue . Below is the full code :- 

package com.sks.softsolution.example;

import java.util.List;

public class ProducerThread implements Runnable {

private final List<Integer> taskQueue;
private final int MAX_CAPACITY;
public ProducerThread(List<Integer> sharedQueue, int size)
{
this.taskQueue = sharedQueue;
this.MAX_CAPACITY = size;
}
@Override
public void run() {
int counter = 0;
while (true)
{
try
{
ProduceTask(counter++);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
private void ProduceTask(int i) throws InterruptedException
{
synchronized (taskQueue)
{
while (taskQueue.size() == MAX_CAPACITY)
{
System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size());
taskQueue.wait();//calling wait on taskQueue lock
}
Thread.sleep(1000);
taskQueue.add(i);
System.out.println("Produced: " + i);
taskQueue.notifyAll();
}
}
}


ConsumerThread.java is consuming task produced by Producer.java Below is the full code:-
package com.sks.softsolution.example;

import java.util.List;

public class ConsumerThread implements Runnable
{
private final List<Integer> taskQueue;
public ConsumerThread(List<Integer> sharedQueue)
{
this.taskQueue = sharedQueue;
}
@Override
public void run()
{
while (true)
{
try
{
consumeTask();
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
private void consumeTask() throws InterruptedException
{
synchronized (taskQueue)
{
while (taskQueue.isEmpty())
{
System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size());
taskQueue.wait();
}
Thread.sleep(1000);
int i = (Integer) taskQueue.remove(0);
System.out.println("Consumed: " + i);
taskQueue.notifyAll();
}
}
}
Now finally we have to start producer and consumer thread
package com.sks.softsolution.example;

import java.util.ArrayList;
import java.util.List;

public class ProducerConsumerExampleWithWaitAndNotify {
public static void main(String[] args) {
List<Integer> taskQueue = new ArrayList<Integer>();
int MAX_CAPACITY = 7;
Thread tProducer = new Thread(new ProducerThread(taskQueue, MAX_CAPACITY), "Producer");
Thread tConsumer = new Thread(new ConsumerThread(taskQueue), "Consumer");
tProducer.start();
tConsumer.start();
}

}
Output of this program 
Queue is empty Consumer is waiting , size: 0
Produced: 0
Produced: 1
Produced: 2
Produced: 3
Produced: 4
Produced: 5
Produced: 6
Queue is full Producer is waiting , size: 7
Consumed: 0
Consumed: 1
Consumed: 2
Consumed: 3
Consumed: 4
Consumed: 5
Consumed: 6
Queue is empty Consumer is waiting , size: 0
Produced: 7
Produced: 8
Produced: 9
Produced: 10
Produced: 11
Produced: 12
Produced: 13
Queue is full Producer is waiting , size: 7
Consumed: 7
Consumed: 8
Please provide your valuable feedback in comment section. it will help me to do my best.
Happy Coding!!!.....

1 comment:

  1. hello,
    i just want to say that you have clearly mention the process very clearly and i also found it is very much easy to understand. keep sharing.

    iphone app development company in chennai

    ReplyDelete

Build a Custom Kernel Module for Android

Hi Guys!!!Hope you are doing well !!!. Today I will describe how you can write a custom kernel module(Hello world) for Android and load it a...