Inter-thread communication in Java enables threads to coordinate their execution by signaling each other during runtime. It is mainly used when multiple threads depend on shared resources or need to work in a specific sequence.
- Helps avoid busy waiting and improves resource utilization
- Ensures proper execution order among dependent threads
- Commonly used in producer-consumer type problems
Note: Inter-thread communication is also known as Cooperation in Java.
Polling
Polling is the process of repeatedly checking a condition in a loop until it becomes true. Once the condition is satisfied, the required action is performed. It is commonly used when one thread waits for another to produce or update data.
Problem with Polling
- Wastes CPU cycles due to continuous condition checking
- Reduces efficiency and slows down overall execution
- Keeps the thread busy instead of allowing other tasks to run
How Java Multithreading Handle Polling
Java avoids polling by using built-in communication methods that allow threads to wait efficiently instead of continuously checking a condition. These methods are defined in the Object class and must be used within a synchronized context.
- wait(): Releases the lock and puts the thread into a waiting state until notified
- notify(): Wakes up one waiting thread (does not release the lock immediately)
- notifyAll(): Wakes up all waiting threads on the same object
The image below demonstrates the concept of Thread Synchronization and Inter-Thread Communication in Java

Producer-Consumer Problem
The Producer-Consumer problem involves two threads where one (producer) adds data to a shared queue and the other (consumer) removes data from it. Proper coordination is required to ensure the producer doesn’t add when the queue is full and the consumer doesn’t remove when it’s empty.
- Uses wait(), notify(), and notifyAll() for synchronization
- Ensures efficient communication between producer and consumer threads
- Prevents issues like data inconsistency and unnecessary waiting
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.
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");
}
}
Output:
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
...Explanation: The program uses a shared queue for communication between producer and consumer threads. The producer adds items and waits if the queue is full, while the consumer removes items and waits if it is empty. Synchronization ensures only one thread accesses the queue at a time. The wait() method pauses execution until notified, and notifyAll() wakes up waiting threads. Both threads run continuously, with Thread.sleep() simulating processing delay.