Medium java java-21

What is the difference between ExecutorService and ForkJoinPool?

The 30 second answer

ExecutorService is the general interface for running tasks on a pool; the classic version, ThreadPoolExecutor, has workers that take tasks from one shared queue. ForkJoinPool is one implementation built for work stealing: each worker has its own queue, and idle workers steal tasks from busy ones. It fits divide-and-conquer and many small tasks. Parallel streams and default CompletableFuture async calls use its common pool.

ExecutorService io = Executors.newFixedThreadPool(32);            // ThreadPoolExecutor
ExecutorService vt = Executors.newVirtualThreadPerTaskExecutor(); // Java 21

class Sum extends RecursiveTask<Long> {
    final long[] a; final int lo, hi;
    Sum(long[] a, int lo, int hi) { this.a = a; this.lo = lo; this.hi = hi; }
    protected Long compute() {
        if (hi - lo < 10_000) { long s = 0; for (int i = lo; i < hi; i++) s += a[i]; return s; }
        int mid = (lo + hi) >>> 1;
        Sum left = new Sum(a, lo, mid); left.fork();
        return new Sum(a, mid, hi).compute() + left.join();
    }
}
long total = ForkJoinPool.commonPool().invoke(new Sum(arr, 0, arr.length));
  • ThreadPoolExecutor: core/max pool size, a work queue and a rejection policy. Good for independent, coarse tasks, including blocking ones.
  • ForkJoinPool: per-worker deques; a worker processes its own tasks and steals from others when idle. Good for recursive splitting. It also implements ExecutorService.
  • The common pool's default parallelism is one less than the number of available processors. Blocking inside it slows every parallel stream in the JVM. [Opinion] Use separate executors for blocking I/O.

Sources: ForkJoinPool Javadoc, ExecutorService Javadoc, ThreadPoolExecutor Javadoc

Sources (0)
See inline citations in the answer above.