Definition
ExecutorServiceis a Java interface for executing tasks asynchronously using a managed pool of worker threads.
Why use it?
Instead of creating threads manually with new Thread(...), ExecutorService lets us:
- reuse threads
- limit the number of concurrent workers
- submit tasks conveniently
- manage shutdown in a structured way
This usually makes concurrent code simpler and more efficient.
Common creation patterns
import java.util.concurrent.*;
ExecutorService fixed = Executors.newFixedThreadPool(4);
ExecutorService single = Executors.newSingleThreadExecutor();
ExecutorService cached = Executors.newCachedThreadPool();Different pools are useful for different workloads:
- fixed thread pool: stable number of worker threads
- single thread executor: tasks run one after another
- cached thread pool: flexible number of threads for short-lived tasks
execute() vs submit()
Two common ways to send work to an executor are:
execute(Runnable task): fire-and-forget, no return valuesubmit(...): returns a Future <> for tracking completion, cancellation, or a result.
Examples:
pool.execute(() -> System.out.println("hello"));
Future<Integer> f = pool.submit(() -> 42);submit(Runnable) also returns a Future<?>, even though the task itself does not produce a useful value.
Example
import java.util.concurrent.*;
ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Integer> result = pool.submit(() -> {
return 21 + 21;
});
int value = result.get();
pool.shutdown();Here:
- the task runs in the thread pool
result.get()waits until the computation finishesshutdown()tells the executor to stop accepting new tasks
Lifecycle management
Important methods:
shutdown(): stop accepting new tasks, finish already submitted tasksshutdownNow(): try to stop immediately, often by interrupting workersawaitTermination(...): wait until the pool has actually terminated
Failing to shut down an executor can leave background threads running.
Related interfaces
Callable<V>: likeRunnable, but returns a value and may throw checked exceptionsScheduledExecutorService: for delayed or periodic tasks
For divide-and-conquer parallelism, Java also provides Fork-Join Framework, whose ForkJoinPool is a specialized executor.
Important
ExecutorServiceis a general-purpose abstraction for task execution. It separates what work should be done from which thread actually runs it.