Inter-thread Communication in Java
Last Updated :
18 Apr, 2025
Inter-thread communication in Java is a mechanism in which a thread is paused from running in its critical section, and another thread is allowed to enter (or lock) the same critical section to be executed.
Note: Inter-thread communication is also known as Cooperation in Java.
What is Polling, and What are the Problems with it?
The process of testing a condition repeatedly till it becomes true is known as polling. Polling is usually implemented with the help of loops to check whether a particular condition is true or not. If it is true, a certain action is taken. For example, in a classic queuing problem where one thread is producing data, and the other is consuming it.
Problem with Polling:
- This wastes many CPU cycles and makes the implementation inefficient.
- This slows down the execution, and it keeps on checking the condition repeatedly.
How does Java Multi-Threading Tackle this problem?
To avoid polling, Java uses three methods, namely, wait(), notify(), and notifyAll(). All these methods belong to the object class, so all classes have them. They must be used within a synchronized block only.
- wait(): It tells the calling thread to give up the lock and go to sleep until some other thread enters the same monitor and calls notify().
- notify(): It wakes up one single thread called wait() on the same object. It should be noted that calling notify() does not give up a lock on a resource.
- notifyAll(): It wakes up all the threads called wait() on the same object.
The image below demonstrates the concept of Thread Synchronization and Inter-Thread Communication in Java:

Producer-Consumer Problem
Now, we are going to understand what producer-consumer problem is. In this one thread add items to a queue and the another thread removes items from the queue. We are going to use wait(), notify() and nortifyAll() methods to ensure that both threads operate efficiently
Example: A simple Java program to demonstrate the three methods. Please note that this program might only run in offline IDEs as it contains taking input at several points.
Java
import java.util.LinkedList;
import java.util.Queue;
public class Geeks {
// Shared queue used by both producer and consumer
private static final Queue<Integer> queue = new LinkedList<>();
// Maximum capacity of the queue
private static final int CAPACITY = 10;
// Producer task
private static final Runnable producer = new Runnable() {
public void run() {
while (true) {
synchronized (queue) {
// Wait if the queue is full
while (queue.size() == CAPACITY) {
try {
System.out.println("Queue is at max capacity");
queue.wait(); // Release the lock and wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Add item to the queue
queue.add(10);
System.out.println("Added 10 to the queue");
queue.notifyAll(); // Notify all waiting consumers
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
// Consumer task
private static final Runnable consumer = new Runnable() {
public void run() {
while (true) {
synchronized (queue) {
// Wait if the queue is empty
while (queue.isEmpty()) {
try {
System.out.println("Queue is empty, waiting");
queue.wait(); // Release the lock and wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Remove item from the queue
System.out.println("Removed " + queue.remove() + " from the queue");
queue.notifyAll(); // Notify all waiting producers
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
public static void main(String[] args) {
System.out.println("Main thread started");
// Create and start the producer thread
Thread producerThread = new Thread(producer, "Producer");
// Create and start the consumer thread
Thread consumerThread = new Thread(consumer, "Consumer");
producerThread.start();
consumerThread.start();
System.out.println("Main thread exiting");
}
}
Explanation of the above Program:
Queue Initialization:
private static final Queue<Integer> queue = new LinkedList<>();
private static final int CAPACITY = 10;
A shared queue (LinkedList implementation) is defined with a capacity of 10. This queue will be used by both producer and consumer threads to add and remove items.
Producer Runnable:
private static final Runnable producer = new Runnable() {
public void run() {
while (true) {
synchronized (queue) {
while (queue.size() == CAPACITY) {
try {
System.out.println("Queue is at max capacity");
queue.wait(); // Release the lock and wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(10);
System.out.println("Added 10 to the queue");
queue.notifyAll(); // Notify all waiting consumers
try {
Thread.sleep(2000); // Simulate some delay in production
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
- Infinite Loop: The producer runs in an infinite loop, continuously producing items.
- Synchronization: The block is synchronized on the shared queue to ensure thread safety.
- Capacity Check: If the queue is full (queue.size() == CAPACITY), the producer waits (queue.wait()) until notified by a consumer.
- Add Item: If there is space in the queue, the producer adds an item (queue.add(10)).
- Notify Consumers: After adding an item, it notifies all waiting consumers (queue.notifyAll()).
- Simulate Delay: The producer sleeps for 2 seconds to simulate the production time (Thread.sleep(2000)).
Consumer Runnable:
private static final Runnable consumer = new Runnable() {
public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
System.out.println("Queue is empty, waiting");
queue.wait(); // Release the lock and wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Removed " + queue.remove() + " from the queue");
queue.notifyAll(); // Notify all waiting producers
try {
Thread.sleep(2000); // Simulate some delay in consumption
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
- Infinite Loop: The consumer runs in an infinite loop, continuously consuming items.
- Synchronization: The block is synchronized on the shared queue to ensure thread safety.
- Empty Check: If the queue is empty (queue.isEmpty()), the consumer waits (queue.wait()) until notified by a producer.
- Remove Item: If there are items in the queue, the consumer removes an item (queue.remove()).
- Notify Producers: After removing an item, it notifies all waiting producers (queue.notifyAll()).
- Simulate Delay: The consumer sleeps for 2 seconds to simulate the consumption time (Thread.sleep(2000)).
Main Method:
public static void main(String[] args) {
System.out.println("Main thread started");
// Create and start the producer thread
Thread producerThread = new Thread(producer, "Producer");
// Create and start the consumer thread
Thread consumerThread = new Thread(consumer, "Consumer");
producerThread.start();
consumerThread.start();
System.out.println("Main thread exiting");
}
- Main Thread Start: The main method starts by printing a message.
- Create Threads: Two threads are created one for the producer and the another one is for consumer
Thread producerThread = new Thread(producer, "Producer")
Thread consumerThread = new Thread(consumer, "Consumer")
- Start Threads: Now, both threads are start
producerThread.start()
consumerThread.start()
- Main Thread Exit: The main method prints an exit message and terminates.
Output:
The program will produce output similar to this:
Main thread started
Main thread exiting
Queue is empty, waiting
Added 10 to the queue
Removed 10 from the queue
Queue is empty, waiting
Added 10 to the queue
Removed 10 from the queue
...
Here, the output demonstrates the interaction between the producer and consumer. The producer adds items to the queue, and the consumer removes them, if the queue is full the producer waits and if the queue is empty the consumer waits. This show how two thread commuincate with each other without wasting time using wait() and notifyAll().
Similar Reads
Multithreading in Java Multithreading is a Java feature that allows the concurrent execution of two or more parts of a program for maximum utilization of the CPU. Each part of such a program is called a thread. So, threads are lightweight processes within a process.Different Ways to Create ThreadsThreads can be created by
3 min read
Lifecycle and States of a Thread in Java A thread in Java can exist in any one of the following states at any given time. A thread lies only in one of the shown states at any instant:New StateRunnable StateBlocked StateWaiting StateTimed Waiting StateTerminated StateThe diagram below represents various states of a thread at any instant:Lif
5 min read
Main thread in Java Java provides built-in support for multithreaded programming. A multi-threaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution.When a Java program starts up, one thread begins running i
4 min read
Java Concurrency - yield(), sleep() and join() Methods In this article, we will learn what is yield(), join(), and sleep() methods in Java and what is the basic difference between these three. First, we will see the basic introduction of all these three methods, and then we compare these three. We can prevent the execution of a thread by using one of th
5 min read
Inter-thread Communication in Java Inter-thread communication in Java is a mechanism in which a thread is paused from running in its critical section, and another thread is allowed to enter (or lock) the same critical section to be executed.Note: Inter-thread communication is also known as Cooperation in Java.What is Polling, and Wha
6 min read
Java Thread Class Thread is a line of execution within a program. Each program can have multiple associated threads. Each thread has a priority which is used by the thread scheduler to determine which thread must run first. Java provides a thread class that has various method calls to manage the behavior of threads b
5 min read
What does start() function do in multithreading in Java? We have discussed that Java threads are typically created using one of the two methods : (1) Extending thread class. (2) Implementing RunnableIn both the approaches, we override the run() function, but we start a thread by calling the start() function. So why don't we directly call the overridden ru
2 min read
Java Thread Priority in Multithreading Java being Object-Oriented works within a Multithreading environment in which the thread scheduler assigns the processor to a thread based on the priority of the thread. Whenever we create a thread in Java, it always has some priority assigned to it. Priority can either be given by JVM while creatin
5 min read
Joining Threads in Java java.lang.Thread class provides the join() method which allows one thread to wait until another thread completes its execution. If t is a Thread object whose thread is currently executing, then t.join() will make sure that t is terminated before the next instruction is executed by the program. If th
3 min read
Java Naming a Thread and Fetching Name of Current Thread A thread can be referred to as a lightweight process. Assigning descriptive names to threads enhances code readability and simplifies debugging. Now let us discuss the different ways to name a thread in Java.Methods to Set the Thread NameThere are two ways by which we can set the name either be it d
4 min read