Java Executor Framework
In this page:
ExecutorService executor = Executors.newFixedThreadPool(n);
executor.submit(task);
executor.shutdown();
What is the Executor Framework?
The Executor framework is a built-in concurrency library introduced in Java 5 that manages thread pools, task queues, and scheduling automatically. It removes the need to manually create, start, and track Thread objects yourself, which becomes error-prone once an application needs more than a handful of concurrent tasks.
Example: What is the Executor Framework?
// Import java.util.concurrent.ExecutorService so it can be used by its short name
import java.util.concurrent.ExecutorService;
// Import java.util.concurrent.Executors so it can be used by its short name
import java.util.concurrent.Executors;
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a thread pool to run tasks
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> System.out.println("Task managed by the pool"));
executor.shutdown();
}
}
Login to try C/C++/Java/PHP code in the editor
Single Thread Executor
A Single Thread Executor manages exactly one background worker thread and executes every submitted task sequentially, strictly in the order those tasks were submitted. This gives you the safety of single-threaded execution — no race conditions between tasks — while still keeping that work off the calling thread.
Example: Single Thread Executor
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2")); // runs after Task 1, same worker
executor.shutdown();
}
}
Login to try C/C++/Java/PHP code in the editor
Fixed Thread Pool
A Fixed Thread Pool manages a set number of worker threads and hands submitted tasks to whichever thread is free, reusing each thread across many tasks instead of spawning a new one every time. This bounds resource usage predictably, which matters a lot under heavy or bursty load.
Example: Fixed Thread Pool
// Import java.util.concurrent.ExecutorService so it can be used by its short name
import java.util.concurrent.ExecutorService;
// Import java.util.concurrent.Executors so it can be used by its short name
import java.util.concurrent.Executors;
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a thread pool to run tasks
ExecutorService executor = Executors.newFixedThreadPool(3);
// Loop: repeat while the condition holds
for (int i = 1; i <= 5; i++) {
// Declare taskId and set it to i
int taskId = i;
executor.submit(() -> System.out.println("Task " + taskId));
}
executor.shutdown();
}
}
Login to try C/C++/Java/PHP code in the editor
Submitting Callable Tasks
Unlike the Runnable interface, the Callable interface represents tasks that can return a computed result and can throw checked exceptions during execution. Submitting a Callable to an executor gets you back a Future you can use to retrieve that result once the task finishes.
Example: Submitting Callable Tasks
// Import java.util.concurrent.* so it can be used by its short name
import java.util.concurrent.*;
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) throws Exception {
// Create a thread pool to run tasks
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> task = () -> 10 + 20;
Future<Integer> future = executor.submit(task);
// Print a line to the console
System.out.println(future.get());
executor.shutdown();
}
}
Login to try C/C++/Java/PHP code in the editor
Shutting Down Executors
Always explicitly shut down executors you create, since their worker threads would otherwise keep the JVM alive indefinitely. Call shutdown() to stop accepting new tasks while letting already-submitted ones finish normally, or shutdownNow() when you need everything to stop immediately.
Example: Shutting Down Executors
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> System.out.println("Task running"));
executor.shutdown(); // stop accepting new tasks, finish existing ones
}
}
Login to try C/C++/Java/PHP code in the editor
- Forgetting to call
shutdown()on the executor, so its non-daemon worker threads keep the JVM from exiting. - Calling
future.get()right after eachsubmit, which makes the tasks run one after another instead of in parallel. - Using
submitwith a Runnable that throws and never checking the Future, since the exception is stored in the Future and silently lost.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: