Demystifying the Java Threads: Inter Thread Communication and Synchronization

Farrukh Masroor
4 min readMar 9, 2024

--

In this third lesson of our series on Java Threads, we will now look into the concept of how threads communicate with each other, and how synchronized blocks work. Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other.

Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed.

What we will learn in this lesson:

synchronized method and blocks in Java

what is monitor

Different methods used in Java for thread communication

As we have discussed in our previous lesson Life Cycle of Java Threads about the synchronized block it is a piece of code that has to be run by a single thread at a time otherwise it may lead to inconsistencies.

When we use a synchronized block, Java internally uses a monitor, also known as a monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object; therefore, all synchronized blocks of the same object can have only one thread executing them at the same time.

In Java, we can use synchronization at the method level and block level

public synchronized void  syncMethod() throws InterruptedException {
System.out.println("Starting the synchronize code for thread "+Thread.currentThread().getName());
}
public void syncBlock(){
System.out.println("This is a non sync block of code multiple threads can execute this line concurrently");
synchronized (this){
System.out.println("This is a synchronized block, only a single thread can execute this line at a time.");
}
}

What is a monitor?

Imagine a monitor as a tool that helps threads (think of them as small workers in a factory) work together smoothly. It has two important jobs:

  1. Mutual Exclusion: This means only one thread can use a particular part of the code (like a machine in a factory) at a time. It’s like a lock on a door that only one person can unlock and enter.
  2. Cooperation: Sometimes, threads need to wait for something to happen before they can continue. It’s as if a machine can only start when all its parts are ready. The monitor helps threads wait until everything is set up correctly.

In simple terms, a monitor helps threads take turns and work together efficiently, just like workers in a well-managed factory.

Different methods used in Java for thread communication

In Java wait(), notify(), and notifyAll() are key methods used in synchronized blocks that enable collaboration between threads. All these methods are defined in the Object class.

wait: The wait() method causes the current thread to release the lock and wait until either another thread invokes the notify() method or the notifyAll() method for this object or a specified amount of time has elapsed.

The current thread must own this object’s monitor, so it must be called from the synchronized method only otherwise it will throw an exception.

There are three variants of the wait method:

public final void wait() throws InterruptedException

public final void wait(long timeout) throws InterruptedException

public final void wait(long timeoutMillis, int nanos) throws InterruptedException

notify: The notify() method 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 arbitrary and occurs at the discretion of the implementation.

public final void notify()

notifyAll: Wakes up all threads that are waiting on this object’s monitor.

public final void notifyAll()

But why these methods are defined in the Object Class and not in the Thread class like other methods sleep, resume, and join?

The reason is that in Java, locks operate on objects, not on Threads. The object itself is the entity shared between threads, allowing them to communicate. Threads run asynchronously and have no specific knowledge of each other. When they lock, wait, and notify, they do so on the object they want to access. Threads do not need to know the status of other threads or even which thread is waiting for the resource. They simply notify the resource, and any thread waiting for it will be notified.

If wait() and notify() were on the Thread class instead, each thread would have to be aware of the status of every other thread. For example, if thread1 needed to notify thread2, it would have to somehow know that thread2 was waiting for access to a specific resource. This would require a mechanism for threads to register the resources or actions they need so that other threads could signal them when the necessary conditions were met or resources became available.

So now we have an understanding of the basics concepts of Java Threads it’s time to implement this knowledge into some real-world problems,in our next lesson we will solve a very classic thread synchronization problem “Producer and Consumer Problem”

--

--

Farrukh Masroor

Welcome to my corner of the tech world! I'm Farrukh Masroor, a seasoned software engineer with a passion for all things technology.