Wait() and notify() methods in java - Definition, 8 key features, solving consumer producer problem with & without these methods and consequences of not using wait() and notify() methods.


Contents of page :
  1. Definition and key features of wait() and notify() methods.
  2. Solving consumer producer problem with wait() and notify() methods.
  3. And consequences of not using wait() and notify() methods.
  4. Solving consumer producer problem without wait() and notify() methods.


Definition and 8 key features >

  • Definitions :
notify() - Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is random and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
notifyAll() - Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.

wait() - Causes the current thread to wait until another thread invokes the notify() or notifyAll() method for this object.
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify()/ notifyAll() method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

  • Thread state :
>By calling wait() method thread go from running to waiting state. In waiting state it will wait for other threads to release object monitor/lock.
> Once notify() or notifyAll() method is called object monitor/lock becomes available and thread can again return to runnable state.


  • synchronized block : thread needs to to acquire object lock before calling wait() and notify() methods i.e. these methods can be called only from synchronized block or synchronized method.

  • Exception : As mentioned above before calling these methods thread must own object’s monitor means wait() and notify() methods must be called from synchronized blocks or synchronized method otherwise IllegalMonitorStateException is thrown at runtime.

  • Waiting time : wait() and notify() method have got few options.
    1. wait() - It internally calls wait(0).

    1. wait(long timeout) - Causes the current thread to wait until either another thread invokes the notify() or notifyAll() methods for this object, or a specified timeout time has elapsed.
public final native void wait(long timeout) throws InterruptedException;

    1. wait(long timeout, int nanos) - Causes the current thread to wait until either another thread invokes the notify() or notifyAll() methods for this object, or a specified timeout time plus the specified number of nanoseconds has elapsed.
public static native void wait(long timeout,int nanos) throws InterruptedException;

   public final native void notify();
   public final native void notifyAll();

  • Instance methods : wait() and notify() are instance methods and are always called on objects.

  • Native methods : implementation of wait() and notify() methods are provided by JVM.
Let’s see definition of wait() and notify() method as given in java.lang.Object -
   public final void wait() throws InterruptedException

   public final native void notify();
   public final native void notifyAll();


  • Belongs to which class : wait() and notify() methods belongs to java.lang.Object class.


Below i tried to give a very simple example to show usgae of wait() and notify() method to give you better understanding of these methods.


Solve Consumer Producer problem by using wait() and notify() methods, where consumer can consume only when production is over.
Producer will allow consumer to consume only when 10 products have been produced (i.e. when production is over).

Thought, we can solve this producer consumer problem without using wait() and notify() method as well, below i have  given consequences of not using using wait() and notify().

In program consumer thread will start() and wait by calling wait() method till producer is producing. Once production is over, producer thread will call notify() method, which will notify consumer thread and consumer will start consuming.
import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
   ArrayList<Integer> sharedQueue;
  
   Producer(){
          sharedQueue=new ArrayList<Integer>();
   }
  
   @Override
   public void run(){
         
          synchronized (this) {
                 for(int i=1;i<=10;i++){ //Producer will produce 10 products
                       sharedQueue.add(i);
                       System.out.println("Producer is still Producing, Produced : "+i);
                      
                       try{
                              Thread.sleep(1000);
                       }catch(InterruptedException e){e.printStackTrace();}
                
                 }
                 System.out.println("Production is over, consumer can consume.");
                 this.notify();    //Production is over, notify consumer thread so that consumer can consume.
          }
   }
  
}
class Consumer extends Thread{
   Producer prod;
  
   Consumer(Producer obj){
    prod=obj;
   }
  
   public void run(){
          /*
          * consumer will wait till producer is producing.
          */
          synchronized (this.prod) {  
                
                 System.out.println("Consumer waiting for production to get over.");
                   try{
                       this.prod.wait();  
                       }catch(InterruptedException e){e.printStackTrace();}
                
          }
         
         
          /*production is over, consumer will start consuming.*/
          int productSize=this.prod.sharedQueue.size();
          for(int i=0;i<productSize;i++)
                 System.out.println("Consumed : "+ this.prod.sharedQueue.remove(0) +" ");  
         
   }
  
}
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class ProducerConsumerWithWaitNotify {
   public static void main(String args[]) throws InterruptedException{
         
          Producer prod=new Producer();
          Consumer cons=new Consumer(prod);
         
      Thread prodThread=new Thread(prod,"prodThread");
          Thread consThread=new Thread(cons,"consThread");
         
          consThread.start();     //start consumer thread.
          Thread.sleep(100);      //This minor delay will ensure that consumer thread starts before producer thread.
          prodThread.start();     //start producer thread.
         
         
   }
}
/*OUTPUT
Consumer waiting for production to get over.
Producer is still Producing, Produced : 1
Producer is still Producing, Produced : 2
Producer is still Producing, Produced : 3
Producer is still Producing, Produced : 4
Producer is still Producing, Produced : 5
Producer is still Producing, Produced : 6
Producer is still Producing, Produced : 7
Producer is still Producing, Produced : 8
Producer is still Producing, Produced : 9
Producer is still Producing, Produced : 10
Production is over, consumer can consume.
Consumed : 1
Consumed : 2
Consumed : 3
Consumed : 4
Consumed : 5
Consumed : 6
Consumed : 7
Consumed : 8
Consumed : 9
Consumed : 10
*/



But what could be consequences of not using using wait() and notify() to solve above producer consumer problem?
It will cost of us performance. Consumer thread will unnecessarily repeatedly check whether producer has completed it’s production or not, but when wait() and notify() were used, consumer thread started, called wait() and waited for producer thread to notify.
Let’s identify Problem statement in not using wait() and notify()>
while(this.prod.productionInProcess)

Using while loop is the actual problem statement in not using wait() and notify(), loops generally costs us performance and we must try to avoid loops.
Let’ say producer was to producer 100 products and for every production it takes 10 seconds & consumer is checking after every 20seconds whether production is over or not. In that case consumer will check after every every 2 products produced whether production is over or not, unnecessary 50 calls will be made, which will of course slow down our whole process.



But now, let's solve above problem without using wait() and notify()  - approach which won’t be performance friendly (but provides developers a choice to solve producer consumer problem in different manner).

How to solve Consumer Producer problem without using wait() and notify() methods, where consumer can consume only when production is over.

Producer will allow consumer to consume only when 10 products have been produced (i.e. when production is over).

We will approach by keeping one boolean variable productionInProcess and initially setting it to true, and later when production will be over we will set it to false.

In program producer thread will start() and it will start producing  and called sleep(1000) in between, which will give consumer thread chance to execute. consumer checks whether productionInProcess is true or not, if it's true,
consumer will sleep(4000) and wake up after specified time and again check whether productionInProcess is true or false. process will repeat till productionInProcess is true. Meanwhile, producer thread will complete production and ultimately make productionInProcess to false. Once productionInProcess is false, consumer will consume.

import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
  
   boolean productionInProcess;
   ArrayList<Integer> list;
  
   Producer(){
          productionInProcess=true;  //initially Producer will be producing, so make this productionInProcess true.
          list=new ArrayList<Integer>();
   }
  
   @Override
   public void run(){
  
          for(int i=1;i<=10;i++){ //Producer will produce 10 products
                 list.add(i);
                 System.out.println("Producer is still Producing, Produced : "+i);
                
                 try{
                       Thread.sleep(1000);
                 }catch(InterruptedException e){e.printStackTrace();}
         
          }
          productionInProcess=false; // Once production is over, make this productionInProcess false.
                                       //Production is over, consumer can consume.
         
   }
  
}
class Consumer extends Thread{
   Producer prod;
  
   Consumer(Producer obj){
    prod=obj;
   }
  
   public void run(){
          /*
          * consumer checks whether productionInProcess is true or not, if it's true,
          * consumer will sleep and wake up after certain time and again check whether productionInProcess is true or false.
          * process will repeat till productionInProcess is true.
          * Once productionInProcess is false we'll exit below while loop.
          */
          while(this.prod.productionInProcess){ //costing us performance
            System.out.println("Consumer waiting for production to get over.");
            try{
                 Thread.sleep(4000);
            }catch(InterruptedException e){e.printStackTrace();}
         
          }
         
         
          /*productionInProcess is false means production is over, consumer will start consuming. */
          System.out.println("Production is over, consumer can consume.");
          int productSize=this.prod.list.size();
          for(int i=0;i<productSize;i++)
                 System.out.println("Consumed : "+ this.prod.list.remove(0) +" ");
         
   }
  
}
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class ProducerConsumerWithoutWaitNotify {
   public static void main(String args[]){
         
          Producer prod=new Producer();
          Consumer cons=new Consumer(prod);
         
          Thread prodThread=new Thread(prod,"prodThread");
          Thread consThread=new Thread(cons,"consThread");
         
          prodThread.start();     //start producer thread.
          consThread.start();     //start consumer thread.
         
         
   }
}
/*OUTPUT
Consumer waiting for production to get over.
Producer is still Producing, Produced : 1
Producer is still Producing, Produced : 2
Producer is still Producing, Produced : 3
Producer is still Producing, Produced : 4
Producer is still Producing, Produced : 5
Producer is still Producing, Produced : 6
Producer is still Producing, Produced : 7
Producer is still Producing, Produced : 8
Producer is still Producing, Produced : 9
Producer is still Producing, Produced : 10
Production is over, consumer can consume.
Consumed : 1
Consumed : 2
Consumed : 3
Consumed : 4
Consumed : 5
Consumed : 6
Consumed : 7
Consumed : 8
Consumed : 9
Consumed : 10
*/






RELATED LINKS>

Race Condition >

Race condition in multithreading and it's solution



Important Thread methods (salient features, usage with programs)>

Join() method - ensure all threads that started from main must end in order in which they started and also main should end in last. Types of join() method-10 salient features of join

Sleep() method in threads - 10 key features with programs

Yield() method in threads - 8 key features with programs

Wait() and notify() methods- Definition, 8 key features, solving consumer producer problem with & without these methods and consequences of not using wait() and notify() methods.

Daemon threads - 12 salient features of Daemon Thread

2 alternate ways to stop thread, as stop() method is deprecated

Using Suspend and resume method in threads



Differences between important thread methods >

Difference between wait() and sleep() method in threads

Differences and similarities between yield() and sleep() in threads

Difference between notify() and notifyAll() methods, with program

Difference between wait() and wait(long timeout) -What will be Thread states



No comments:

Post a Comment