What is inter thread communication in Java example

By | July 24, 2024

Inter thread communication in Java allows the multiple threads to communicate and coordinate with each other. It helps in a concurrent environment when multiple threads work together over shared resources.

In Java, we can use the object’s class methods, such as wait(), notify() and notifyAll() to achieve inter-threaded communication.

  • wait method in Java
    • The wait() method allows the current thread to release the lock and wait until some other thread invokes the notify() or notifyAll() method.
  • notify method in Java
    • It woke up a single thread that is waiting on the object’s monitor.
  • notifyAll method in Java
    • The notifyAll() method wakes up all the threads that are waiting on the object’s monitor.

Object’s monitor

Monitor is the lock that every Java object has, and it controls access to the synchronized block or method. When a thread successfully enters a synchronized block or method, it owns the monitor, which means it has exclusive access to that block or method.

Example of inter thread communication in Java

One of the most prime examples of inter-threaded communication is in banking. If we have two threads, credit-thread and debit-thread, and both are executing to update the balance amount, it may lead to unpredictable behavior if inter-threaded communication is not handled correctly.

Let’s implement the above scenario and understand the workings of inter thread communication.

Java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Banking {
	
	int balance = 1000;
	
	Logger logger = LogManager.getLogger(Banking.class);
	
	public void debit(int amount) {
		this.balance -= amount;
		logger.info("Remaining balance amount: {}", this.balance);
	}
	
	public void credit(int amount) {
		this.balance += amount;
		logger.info("Remaining balance amount: {}", this.balance);
	}
	
	/**
	 * client code
	 */
	public static void main(String[] args) {
		
		Banking banking = new Banking();
		
		// create debit-thread and invoking debit method
		new Thread("debit-thread") {
			public void run() {
				banking.debit(1250);
			}
		}.start();
		
		// create credit-thread and invoke credit method
		new Thread("credit-thread") {
			public void run() {
				banking.credit(1000);
			}
		}.start();
	}
}

In the above program, we can see we have an initial balance of $1,000, and in the debit() method, we are just subtracting the amount from the balance amount, while in the credit() method, we are adding up the amount to the balance amount.

Inter thread communication in Java
Fig 1- Unpredictable behavior

In the above output, we can see we are getting a balance of -$250, which is not possible. We need to design the program in such a way that they can communicate with each other before performing any transactions or operations.

Inter thread communication in Java

We add inter thread communication in the above program; for this, we have used the wait() and notify() methods as follows:

  1. First, we have synchronized our debit() and credit() methods using synchronized keywords. So, only one thread can execute it at a time.
  2. We will be checking if the withdrawn amount is greater than the balance, and we will be calling the wait() method. This will put the debit-thread in a waiting state, and other threads (credit-threads) may get a chance to execute the credit() method.
  3. Similarly, we have synchronized the credit() method and added the credit amount to the balance.
Java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Banking {
	
	int balance = 1000;
	
	Logger logger = LogManager.getLogger(Banking.class);
	
	/**
	 * if the debit amt > balance, then wait() method gets called
	 * and debit-thread goes into waiting state.
	 * 
	 * @param amount
	 */
	public synchronized void debit(int amount) {
		if(this.balance < amount) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.balance -= amount;
		logger.info("Remaining balance amount {}", this.balance);
	}
	
	/**
	 * once the credit-thread deposits the amount and update the 
	 * balance, it will call notify() to let know the monitor threads
	 * its execution is completed.
	 * @param amount
	 */
	public synchronized void credit(int amount) {
		this.balance += amount;
		logger.info("Remaining balance amount {}", this.balance);
		notify();
	}
	
	/**
	 * client code
	 */
	public static void main(String[] args) {
		
		Banking banking = new Banking();
		
		// create debit-thread and invoking debit method
		new Thread("debit-thread") {
			public void run() {
				banking.debit(1250);
			}
		}.start();
		
		// create credit-thread and invoke credit method
		new Thread("credit-thread") {
			public void run() {
				banking.credit(1000);
			}
		}.start();
	}
}

As we are debiting $1250, which is greater than the balance amount ($1000), it will go to a waiting state, and the credit thread will get a chance to credit ($1000) to the balance amount, and then calling the nofity() method will invoke the waiting thread to perform the withdraw scenario.

Inter thread communication in Java
Fig 2- Inter thread communication

Leave a Reply

Your email address will not be published. Required fields are marked *