SyntaxStudy
Sign Up
Java ExecutorService and Thread Pools
Java Beginner 1 min read

ExecutorService and Thread Pools

Creating a new thread for every task is expensive — thread creation has significant overhead in time and memory. ExecutorService decouples task submission from thread management by maintaining a pool of reusable worker threads. You create a pool using the Executors factory class: newFixedThreadPool(n) creates a pool with a fixed number of threads, newCachedThreadPool() creates threads as needed and reuses idle ones, and newSingleThreadExecutor() guarantees sequential execution on a single background thread. Tasks are submitted to an ExecutorService using submit() or execute(). submit() accepts both Runnable and Callable and returns a Future, which represents the pending result. You call future.get() to block until the result is ready, optionally with a timeout. If the task threw an exception, get() wraps it in an ExecutionException. Callable is like Runnable but can return a value and throw checked exceptions, making it suitable for tasks that compute results. Shutting down an ExecutorService correctly is important. shutdown() stops accepting new tasks but lets submitted tasks finish. shutdownNow() attempts to cancel running tasks and returns a list of tasks that were never started. awaitTermination() blocks until all tasks complete or the timeout elapses. Always shut down executor services when you are done with them to avoid thread leaks.
Example
import java.util.*;
import java.util.concurrent.*;

public class ExecutorServiceDemo {

    static int fibonacci(int n) {
        if (n <= 1) return n;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // Fixed thread pool with 3 workers
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // Submit Callable tasks that return results
        List<Future<Integer>> futures = new ArrayList<>();
        int[] inputs = {10, 15, 20, 25, 30};

        for (int n : inputs) {
            Future<Integer> future = executor.submit(() -> fibonacci(n));
            futures.add(future);
        }

        // Collect results
        for (int i = 0; i < inputs.length; i++) {
            try {
                int result = futures.get(i).get(5, TimeUnit.SECONDS);
                System.out.printf("fibonacci(%d) = %d%n", inputs[i], result);
            } catch (TimeoutException e) {
                System.out.println("Task " + i + " timed out");
                futures.get(i).cancel(true);
            }
        }

        // Proper shutdown
        executor.shutdown();
        boolean done = executor.awaitTermination(10, TimeUnit.SECONDS);
        System.out.println("Executor terminated cleanly: " + done);

        // ScheduledExecutorService example
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(
            () -> System.out.println("Tick at " + System.currentTimeMillis()),
            0, 200, TimeUnit.MILLISECONDS);
        Thread.sleep(700);
        scheduler.shutdownNow();
    }
}