Difference between notify vs notifyall in Java - Java @ Desk

Saturday, January 3, 2015

Difference between notify vs notifyall in Java

Difference between notify vs notifyall in Java

Consider a basic Producer Consumer problem where we have 10 consumer threads and only 1 Producer thread. Producer doing some activity (for e.g. creating some singleton objects that will be used by all consumers). Hence all consumers has to wait till the singleton object is created by Producer.

Once producer finished the job of creating singleton object, it can notify the consumer. Now in this case, there are 10 consumers so all the 10 consumers need to be informed that the job is done and you may start processing. In this case we must go for notifyAll().

As explained,
1) notify() is used when a particular 1 thread needs to notify where all the threads will do a similar fashion of job.
2) notifyAll() is used when all the waiting threads needs to notify that have different purpose. In above case of creation of Singleton object, we need to use notifyAll()

In case of notifyAll(), even though the notification is sent to all to start processing, but each thread enters the RUNNING state in some particular random order. The order is defined by the JVM.

I have a scenario, where I have
a) NotifyThread - This thread sleeps for 100ms as soon as it starts. It can be assumed as a PRODUCER class.
b) WaitThread - As soon as this thread starts, it enters into wait state. There are 10 WaitThread that are started simultaneously. The wait is applied on a variable "synVariable".

As soon as NotifyThread sleep is over, it does notifyAll() which notifies all the 10 WaitThread that starts running in some particular random order which is decided by JVM.

I am facing a very weird issue in the code implemented below, where I have 10 Consumers and 1 Producer. When I am using notify() only 1 thread is notified while the rest 9 keep on waiting for infinite amount of time. I need help of the reader how to come out of this issue. Please use the comment section below for suggestions.

NotifyThread.java - There will be 1 object of NotifyThread.
package com.notifyall;

public class NotifyThread implements Runnable {

 @Override
 public void run() {
  try {
   Thread.sleep(100);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  synchronized (synVariable) {
   System.out.println("\n**********Notify Thread Started*********\n");
   synVariable.notifyAll();
  }
 }

 private String synVariable;

 public String getSynVariable() {
  return synVariable;
 }

 public void setSynVariable(String synVariable) {
  this.synVariable = synVariable;
 }
}


WaitThread.java - 10 threads will be created for this object.
package com.notifyall;

public class WaitThread implements Runnable {

 @Override
 public void run() {
  synchronized (synVariable) {
   try {
    System.out.println("WaitThread " + this.getThreadNumber() + " Started." +
      " Waiting for NotifyThread for Notification");
    synVariable.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println("WaitThread " + this.getThreadNumber() + " got Notified");
 }
 
 private String synVariable;

 public String getSynVariable() {
  return synVariable;
 }

 public void setSynVariable(String synVariable) {
  this.synVariable = synVariable;
 }
 
 private int threadNumber;

 public int getThreadNumber() {
  return threadNumber;
 }

 public void setThreadNumber(int threadNumber) {
  this.threadNumber = threadNumber;
 }

}


TestClient.java



package com.notifyall;

public class TestClient {

 public static void main(String args[]) {
  WaitThread[] waitThreads = new WaitThread[10];
  NotifyThread notifyThread = new NotifyThread();
  
  String synVariable = "synVariable";
  
  notifyThread.setSynVariable(synVariable);
  
  for(int i = 0 ; i < 10 ; i++) {
   waitThreads[i] = new WaitThread();
   waitThreads[i].setSynVariable(synVariable);
   waitThreads[i].setThreadNumber(i);
   new Thread(waitThreads[i]).start();
  }
  
  new Thread(notifyThread).start();
 }
}


Output - The Order of Notification may differ in order because it all depends on JVM which thread gets the notification first.
WaitThread 0 Started. Waiting for NotifyThread for Notification
WaitThread 1 Started. Waiting for NotifyThread for Notification
WaitThread 3 Started. Waiting for NotifyThread for Notification
WaitThread 4 Started. Waiting for NotifyThread for Notification
WaitThread 2 Started. Waiting for NotifyThread for Notification
WaitThread 5 Started. Waiting for NotifyThread for Notification
WaitThread 6 Started. Waiting for NotifyThread for Notification
WaitThread 8 Started. Waiting for NotifyThread for Notification
WaitThread 7 Started. Waiting for NotifyThread for Notification
WaitThread 9 Started. Waiting for NotifyThread for Notification

**********Notify Thread Started*********

WaitThread 9 got Notified
WaitThread 7 got Notified
WaitThread 8 got Notified
WaitThread 6 got Notified
WaitThread 5 got Notified
WaitThread 4 got Notified
WaitThread 1 got Notified
WaitThread 0 got Notified
WaitThread 2 got Notified
WaitThread 3 got Notified


To download source, click here






1 comment:

  1. With the tools in java.util.concurrent the use of the class Thread and the Object synchronization methods wait(), notify() and notifyAll(0 should be considered deprecated.
    For the OP the class CyclicBarrier should be used: the consumers will wait at the barrier for the producer to finish and the barrier action is than used to distribute the result of the producer to each of the consumers.
    The OP is NOT a typical producer/consumer pattern as ALL consumers need to get the result of the single producer. In the general C/P pattern ANY consumer gets the producer output. notifyAll() will handle that as expected.

    ReplyDelete