Inter-Thread Communication in Java
Tushar Kumar
Aspiring Software Engineer | Java, Spring Boot, React Enthusiast | Eager to Tackle Real-World Challenges | Ready to Deliver Innovative Solutions as a Fresh Talent | CDAC Certified
In the world of Java multithreading, inter-thread communication is a critical concept. Threads often need to coordinate with each other to ensure smooth execution. While it may sound complex, a simple analogy can make it crystal clear. Let's explore inter-thread communication using the example of a worker and a wrench.
In Java, the methods wait(), notify(), and notifyAll() are the building blocks for inter-thread communication. They are used to synchronize and coordinate threads that share resources.
wait():
notify():
notifyAll():
Understanding the Process of Inter-Thread Communication
1. wait(): The Worker Waits for the Wrench
A worker approaches the shared toolbox but finds that the wrench is already in use. Instead of waiting idly, the worker decides to "pause" and steps aside, signaling that they are ready to use the wrench once it becomes available. This is equivalent to a thread calling the wait() method—it releases the lock and waits for a signal to proceed.
领英推荐
2. notify(): The Wrench is Now Available
When the worker currently using the wrench completes their task, they signal the next waiting worker that the wrench is now available. This is akin to a thread calling the notify() method, waking up one waiting thread to resume execution.
3. notifyAll(): All Workers Get Notified
In certain situations, the supervisor might decide to notify all the waiting workers that they can now access the wrench. This happens when the notifyAll() method is used, waking up all waiting threads. They then compete for the wrench, ensuring no one is left out of the process.
Synchronization Ensures Order
The toolbox, in this example, represents the shared resource, and it is protected by a lock (using the synchronized keyword in Java). This ensures that only one worker (thread) can access the wrench (resource) at any given time, preventing conflicts or misuse.
Why Are wait(), notify(), and notifyAll() Defined in the Object Class Instead of the Thread Class?
These methods are defined in the Object class because they work on the intrinsic lock of an object, not a thread. In Java, every object has a built-in lock that threads can synchronize on. Since wait(), notify(), and notifyAll() are used for communication between threads about the state of an object (e.g., resource availability), they logically belong to the Object class, where the lock resides.
Defining these methods in the Object class ensures any object can be used as a shared resource for thread synchronization, making the design flexible and consistent.
class Wrench {
private boolean isAvailable = false;
// Method to take the wrench
public synchronized void takeWrench(String workerName) throws InterruptedException {
while (!isAvailable) { // If the wrench is unavailable, the thread waits.
System.out.println(workerName + " is waiting for the wrench.");
wait(); // Waits until notified by another thread.
}
isAvailable = false; // Wrench is now taken.
System.out.println(workerName + " took the wrench.");
}
// Method to return the wrench
public synchronized void returnWrench(String workerName) {
isAvailable = true; // Wrench is now available.
System.out.println(workerName + " returned the wrench.");
notify(); // Notify one thread waiting for the wrench.
}
}
class Worker extends Thread {
private final Wrench wrench;
private final String name;
public Worker(Wrench wrench, String name) {
this.wrench = wrench;
this.name = name;
}
@Override
public void run() {
try {
wrench.takeWrench(name); // Try to take the wrench.
Thread.sleep(1000); // Simulate work with the wrench.
wrench.returnWrench(name); // Return the wrench after use.
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class FactorySimulation {
public static void main(String[] args) {
Wrench wrench = new Wrench();
Worker worker1 = new Worker(wrench, "Worker 1");
Worker worker2 = new Worker(wrench, "Worker 2");
Worker worker3 = new Worker(wrench, "Worker 3");
worker1.start();
worker2.start();
worker3.start();
}
}
Output -
Worker 1 is waiting for the wrench.
Worker 2 is waiting for the wrench.
Worker 1 took the wrench.
Worker 1 returned the wrench.
Worker 2 took the wrench.
Worker 2 returned the wrench.
Worker 3 took the wrench.
Worker 3 returned the wrench.