Inter Thread Communication in Java

Inter-thread communication in Java is a technique through which multiple threads communicate with each other.

It provides an efficient way through which more than one thread communicate with each other by reducing CPU idle time. CPU idle time is a process in which CPU cycles are not wasted.

When more than one threads are executing simultaneously, sometimes they need to communicate to each other by exchanging information with each other. A thread exchanges information before or after it changes its state.

There are several situations where communication between threads is important. For example, suppose that there are two threads A and B. Thread B uses data produced by Thread A and performs its task.

If Thread B waits for Thread A to produce data, it will waste many CPU cycles. But if threads A and B communicate with each other when they have completed their tasks, they do not have to wait and check each other’s status every time.

Thus, CPU cycles will not waste. This type of information exchanging between threads is called inter-thread communication in Java.

How to achieve Inter thread communication in Java


Inter thread communication in Java can be achieved by using three methods provided by Object class of java.lang package. They are:
1. wait()
2. notify()
3. notifyAll()

These methods can be called only from within a synchronized method or synchronized block of code otherwise, an exception named IllegalMonitorStateException is thrown.


All these methods are declared as final. Since it throws a checked exception, therefore, you must be used these methods within Java try-catch block.

wait() Method in Java


wait() method in Java notifies the current thread to give up the monitor (lock) and to go into sleep state until another thread wakes it up by calling notify() method. This method throws InterruptedException.

Various forms of wait() method allow us to specify the amount of time a thread can wait. They are as follows:

Syntax:

public final void wait()
public final void wait(long millisecond) throws InterruptedException
public final void wait(long millisecond, long nanosecond) throws InterruptedException

All overloaded forms of wait() method throw InterruptedException. If time is specified in the wait() method, a thread can wait for maximum time.

Note:
1. A monitor is an object which acts as a lock. It is applied to a thread only when it is inside a synchronized method.
2. Only one thread can use monitor at a time. When a thread acquires a lock, it enters the monitor.
3. When a thread enters into the monitor, other threads will wait until first thread exits monitor.
4. A lock can have any number of associated conditions.

notify() Method in Java


The notify() method wakes up a single thread that called wait() method on the same object. If more than one thread is waiting, this method will awake one of them. The general syntax to call notify() method is as follows:

Syntax:

public final void notify()

notifyAll() Method in Java


The notifyAll() method is used to wake up all threads that called wait() method on the same object. The thread having the highest priority will run first. The general syntax to call notifyAll() method is as follows:

Syntax:

public final void notifyAll()

Let us take an example program where a thread uses data delivered by another thread without using wait() and notify() method.

Program source code 1:

public class A 
{
int i;	
 synchronized void deliver(int i)
 {
   this.i = i;	 
   System.out.println("Data Delivered: " +i);	 
 }
 synchronized int receive()
 {
  	System.out.println("Data Received: " + i); 
  	return i;
 }
}
public class Thread1 extends Thread
{
 A obj;
 Thread1(A obj)
 {
  this.obj = obj;
 }
public void run()
{
for(int j = 1; j <= 5; j++){
 obj.deliver(j); 	
}
}
}
public class Thread2 extends Thread 
{
A obj;
Thread2(A obj)
{
 this.obj = obj;
}
public void run()
{
for(int k = 0; k <= 5; k++){
 obj.receive();	
}
 }
}
public class NoCommunication 
{
public static void main(String[] args) 
{
A obj = new A();
Thread1 t1 = new Thread1(obj);
Thread2 t2 = new Thread2(obj);
  t1.start();
  t2.start();
 }
}
Output:
       Data Delivered: 1
       Data Delivered: 2
       Data Delivered: 3
       Data Delivered: 4
       Data Delivered: 5
       Data Received: 5
       Data Received: 5
       Data Received: 5
       Data Received: 5
       Data Received: 5
       Data Received: 5

Explanation:

In this example program, data delivered by Thread1 is used by Thread2. Thread1 produces data 1 to 5 and delivered to Thread2 to receive it but due to no communication between these two threads, Thread2 uses data 5 five times in a row.

Let’s rewrite the above program where we will use wait() and notify() method to establish the communication between two threads.

Program source code 2:

// In this program, we will understand how to use wait and notify.
// It is the most efficient way for thread communication.
public class A 
{
int i;	
boolean flag = false; // flag will be true when data production is over.
synchronized void deliver(int i)
{
 if(flag)
 try
 {
  wait(); // Wait till a notification is received from Thread2. There will be no wastage of time.	 
 }
 catch(InterruptedException ie)
 {
  System.out.println(ie);	 
 }
   this.i = i;	
   flag = true; // When data production is over, it will store true into flag.
   System.out.println("Data Delivered: " +i);
   notify(); // When data production is over, it will notify Thread2 to use it.
 }
synchronized int receive()
{
if(!flag)
try {
 wait(); // Wait till a notification is received from Thread1.	
}
catch(InterruptedException ie){
 System.out.println(ie);	
}
 System.out.println("Data Received: " + I); 
  flag = false; // It will store false into flag when data is received.
  notify(); // When data received is over, it will notify Thread1 to produce next data.
  return i;
 }
}
public class Thread1 extends Thread
{
 A obj;
 Thread1(A obj)
 {
  this.obj = obj;
 }
public void run()
{
for(int j = 1; j <= 5; j++){
 obj.deliver(j); 	
  }
}}
public class Thread2 extends Thread 
{
A obj;
Thread2(A obj)
{
 this.obj = obj;
}
public void run()
{
for(int k = 0; k <= 5; k++){
 obj.receive();	
}
 }}
public class Communication 
{
public static void main(String[] args) 
{
 A obj = new A(); // Creating an object of class A.

// Creating two thread objects and pass reference variable obj as parameter to Thread1 and Thread2.
Thread1 t1 = new Thread1(obj);
Thread2 t2 = new Thread2(obj);
// Run both threads.
  t1.start();
  t2.start();
 }
}
Output:
      Data Delivered: 1
      Data Received: 1
      Data Delivered: 2
      Data Received: 2
      Data Delivered: 3
      Data Received: 3
      Data Delivered: 4
      Data Received: 4
      Data Delivered: 5
      Data Received: 5

Explanation:

1. In this example program, wait() and notify() methods are called inside deliver() and receive() method. Both methods enable Thread1 to notify Thread2 after producing data and wait until Thread2 complete using.

2. In the same way, Thread2 after using data notifies Thread1 and waits until Thread1 produces and delivers the next data. Thus, the output comes in the synchronized form.

3. If the flag is true, Thread2 takes data from Thread1 and use it. When Thread1 is busy producing data, now and then Thread2 will check flag is true or not. If the flag shows false, then Thread2 will wait for the object until it receives a notification from a notify() method.

When the data production is over, Thread1 will send a notification immediately to Thread2 to receive data. In this way, Thread1 and Thread2 communicate with each other efficiently.

Producer-Consumer Problem in Java using wait and notify methods


In the producer and consumer problem, we will use the same technique. It consists of four classes:

  • Q where we will try to synchronize data.
  • Producer where Producer thread will produce data (or some goods).
  • Consumer where Consumer thread will wait for Producer to produce data. When the Producer thread completes the production of data, the Consumer thread will take that data and use it.

Look at the program source code to understand better.

Program source code 3:

// A correct implementation of Producer and Consumer.
public class Q 
{
int i;	
boolean valueSet = false; 
synchronized void produce(int i)
{
if(valueSet)
try
{
  wait();	 
}
catch(InterruptedException ie)
{
  System.out.println(ie);	 
}
 this.i = i;	
 valueSet = true;
System.out.println("Data Produced: " +i);
 notify();
}
synchronized int consume()
{
if(!valueSet)
try {
  wait();	
}
catch(InterruptedException ie){
  System.out.println(ie);	
}
System.out.println("Data Consumed: " + i); 
 valueSet = false;
  notify();
  return I;
  }
}
public class Producer extends Thread
{
Q q;
Producer(Q q)
{
 this.q = q;
 }
public void run()
{
 for(int j = 1; j <= 5; j++){
  q.produce(j); 	
 }
}
}
public class Consumer extends Thread
{
Q q;
Consumer(Q q)
{
  this.q = q;
}
public void run()
{
 for(int k = 0; k <= 5; k++){
  q.consume();	
 }
}
}
public class ThreadCommunication 
{
public static void main(String[] args) 
{
 Q q = new Q();
 
Producer p = new Producer(q);
Consumer c = new Consumer(q);
  p.start();
  c.start();
  }
}
Output:
       Data Produced: 1
       Data Consumed: 1
       Data Produced: 2
       Data Consumed: 2
       Data Produced: 3
       Data Consumed: 3
       Data Produced: 4
       Data Consumed: 4
       Data Produced: 5
       Data Consumed: 5

Most of the threading problems are generally of the category of Producer consumer pattern where one thread is producing data and other thread consume that data. We must know how to establish intercommunication between threads to solve this problem.

Why wait(), notify() and notifyAll() methods are defined inside Object class, not Thread class?


This is because all these three methods are related to lock and Java provides lock at Object level, not at the Thread level. Therefore, they are defined in Object class.

Difference between wait() and sleep() in Java


Object.wait() and Thread.sleep() are entirely two different methods in Java that are used in two different contexts. Here, we have listed a few differences between these two methods.

1. wait() method is always called from synchronized block otherwise, it will throw IllegalMonitorStateException whereas sleep() method can be called from any code block.
2. wait() method releases the acquired lock while sleep() method does not release the lock.
3. wait() is called on Object whereas sleep() is called on Thread.
4. waiting thread can be awakened by invoking notify()/notifyAll() methods while sleeping thread cannot be awakened.
5. wait is a non-static method while sleep is a static method.

Hope that this tutorial has covered inter-thread communication in Java with example programs. I hope that you will have understood this producer-consumer problem.