Inter-thread communication in Java involves the coordination of threads to ensure they work together correctly without conflicts. This is essential in multithreaded applications to avoid issues such as race conditions, deadlocks, and inconsistent data states. Java provides several mechanisms and constructs for inter-thread communication
Understanding Inter-Thread Communication
When multiple threads share a resource, sometimes one thread must pause its execution until another thread completes its work. For example, in a producer-consumer scenario, a consumer thread might have to wait until the producer provides data. Rather than continuously checking (polling) the resource, Java allows a thread to suspend itself and wait until it receives a notification from another thread.
This is where wait()
, notify()
, and notifyAll()
come into play:
-
wait()
causes the current thread to wait until another thread invokesnotify()
ornotifyAll()
on the same object. -
notify()
wakes up a single waiting thread. -
notifyAll()
wakes up all threads waiting on the object’s monitor.
Method Descriptions
1. wait()
public final void wait() throws InterruptedException
Causes the current thread to wait until another thread notifies it.
The thread releases the lock and goes into a waiting state.
Code language: PHP (php)
 2. notify()
public final void notify()
Wakes up one thread waiting on the object's monitor.
The awakened thread must reacquire the lock before resuming execution.
Code language: PHP (php)
 3. notifyAll()
public final void notifyAll()
Wakes up all threads waiting on the object's monitor.
Threads compete for the lock; only one thread acquires it and continues.
Code language: PHP (php)
 Program Implementation
The Producer-Consumer problem is a classic example of a multi-threading synchronization issue, where two or more threads share a common resource. One or more producer threads generate data while one or more consumer threads take data for processing.
//ProducerConsumerDemo.java class SharedResource { private int data; private boolean isDataAvailable = false; // Synchronized produce method for the producer thread public synchronized void produce(int value) { // If data is available, producer has to wait until consumer consumes it while (isDataAvailable) { try { wait(); // Wait until the data is consumed } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Handle thread interruption } } // Produce data data = value; isDataAvailable = true; // Data is now available System.out.println("Produced: " + value); notifyAll(); // Notify all waiting threads (consumer) that new data is available } // Synchronized consume method for the consumer thread public synchronized int consume() { // If no data is available, consumer has to wait until producer produces it while (!isDataAvailable) { try { wait(); // Wait until data is produced } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Handle thread interruption } } // Consume data isDataAvailable = false; // Data is now consumed System.out.println("Consumed: " + data); notifyAll(); // Notify all waiting threads (producer) that the data has been consumed return data; } } public class ProducerConsumerDemo { public static void main(String[] args) { SharedResource resource = new SharedResource(); // Producer thread Thread producer = new Thread(() -> { for (int i = 1; i <= 10; i++) { resource.produce(i); // Produce data } }); // Consumer thread Thread consumer = new Thread(() -> { for (int i = 1; i <= 10; i++) { resource.consume(); // Consume data } }); // Start both producer and consumer threads producer.start(); consumer.start(); } } /* C:\>javac ProducerConsumerDemo.java C:\>java ProducerConsumerDemo Produced: 1 Consumed: 1 Produced: 2 Consumed: 2 Produced: 3 Consumed: 3 Produced: 4 Consumed: 4 Produced: 5 Consumed: 5 Produced: 6 Consumed: 6 Produced: 7 Consumed: 7 Produced: 8 Consumed: 8 Produced: 9 Consumed: 9 Produced: 10 Consumed: 10 */
Inter-thread communication using wait()
, notify()
, and notifyAll()
methods is a powerful and efficient mechanism for coordinating threads in Java. It enables threads to work together smoothly without the need for constant checking or inefficient spinning. Proper understanding and careful use of these methods lead to efficient, synchronized, and deadlock-free multi-threaded programs. Mastery of this concept is essential for writing robust concurrent Java applications.