In multithreading coordination, we often use wait/notify blocks or concurrency queues to print odd and even numbers sequentially. Another advanced approach is leveraging a thread pool manager: **ExecutorService**.
Using ExecutorService helps us decouple task creation from execution threads, managing threads dynamically from a pool.
Imagine a busy restaurant kitchen with a **head dispatcher (the ExecutorService)** and two chefs: Chef 1 (handles odd orders) and Chef 2 (handles even orders).
Instead of the chefs talking to each other directly, the dispatcher maintains a ticket track queue:
- The dispatcher hands ticket `1` (Odd) to Chef 1.
- Once Chef 1 finishes, the dispatcher hands ticket `2` (Even) to Chef 2.
By scheduling tickets sequentially through the dispatcher pool, the kitchen guarantees orders are plated in perfect order without chefs coordinating among themselves.
Java Implementation
By using a thread pool and submitting tasks, we can alternate printing task classes dynamically:
package io.practise.string;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestEvenOddUsingExecutorService {
private static final Object lock = new Object();
private static int number = 1;
private static final int MAX = 20;
public static void main(String[] args) {
// Create a fixed thread pool of 2 threads
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
while (number <= MAX) {
synchronized (lock) {
if (number % 2 == 0) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} else {
System.out.println(Thread.currentThread().getName() + ": " + number++);
lock.notifyAll();
}
}
}
});
executor.submit(() -> {
while (number <= MAX) {
synchronized (lock) {
if (number % 2 != 0) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} else {
System.out.println(Thread.currentThread().getName() + ": " + number++);
lock.notifyAll();
}
}
}
});
executor.shutdown();
}
}
Conclusion
Using `ExecutorService` lets you easily manage threads and submit tasks dynamically, ensuring that threads are automatically recycled when the application completes execution.