JAVA
intro Executor
neal89
2025. 3. 25. 12:59
☕ Java Thread Pool & Executor Framework – Why and How
When building concurrent applications in Java, you might be tempted to create threads manually using new Thread(...).
But in real-world, large-scale systems, this approach introduces several problems.
🚨 Why Not Create Threads Directly?
1. Performance Cost of Thread Creation
- Memory usage: Each thread comes with its own call stack, typically taking up 1MB or more of memory.
- System resource consumption: Creating threads involves system calls, which consume CPU and memory.
- Scheduling overhead: The OS needs to manage the scheduling of each thread, adding additional overhead.
2. Difficult to Manage
- Thread lifecycle, synchronization, and exception handling become hard to control.
- Manual thread creation lacks scalability and maintainability.
3. Runnable Interface is Limited
- It doesn't return a result.
- It can't throw checked exceptions.
- You can't tell when it's done, unless you write extra code.
✅ Why Use the Executor Framework?
The Executor framework provides an abstraction for managing and reusing threads efficiently.
Benefits include:
- Thread pooling – reuse threads instead of creating new ones every time
- Task submission – submit Runnable or Callable tasks without worrying about threads
- Graceful shutdown – stop accepting new tasks and finish all current tasks before shutting down
💡 What is Graceful Shutdown?
Let’s say you’re running a service that handles user orders. If you need to restart the server:
❌ You should not stop it abruptly in the middle of processing orders
✅ You should:
- Reject new tasks
- Wait for all running tasks to finish
- Then shut down
This process is called a graceful shutdown, and ExecutorService supports it easily.
🔧 Example: Using ExecutorService
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
// Submit 3 tasks
for (int i = 1; i <= 3; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Running task " + taskId);
try {
Thread.sleep(1000); // Simulate work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Finished task " + taskId);
});
}
// Graceful shutdown
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow(); // Force shutdown if not done in time
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
System.out.println("All tasks completed. Executor shut down.");
}
}
✅ Summary
❌ Manual Threads ✅ Executor Framework
High memory usage | Reuses threads efficiently |
Hard to manage lifecycle | Easy to submit & control |
No result or error flow | Supports Callable, Future |
No graceful shutdown | Built-in shutdown support |
If you're building scalable, stable applications, using the Executor framework is not just a good idea — it's essential.