multi threading
intermediate

ExecutorService & Thread Pools

Run tasks on a managed thread pool instead of spawning raw threads — bounded resources, reuse, and proper shutdown.

Creating a fresh Thread for every task seems simple but scales badly: thread creation is expensive, each thread consumes roughly a megabyte of stack, and unbounded thread creation under load can exhaust memory and thrash the scheduler. ExecutorService decouples task submission from thread management — you hand it work, and it runs that work on a managed, reusable pool of threads.

A copy shop with 4 photocopiers and a queue of jobs. Customers drop off jobs, get a claim ticket (Future), and pick up the result when done. Closing time: stop accepting new jobs, finish what's in flight.

Key Concepts

1
You typically obtain one from the Executors factory or by constructing a ThreadPoolExecutor directly. Submitting a Runnable or Callable returns immediately, and for a Callable you get a Future you can later block on for the result. The pool keeps a set of worker threads alive and feeds them tasks from a queue, so the cost of thread creation is paid once and amortised across many tasks. The core parameters — core and maximum pool size, the work queue, the keep-alive time, and the rejection policy — let you tune behaviour: a fixed pool bounds concurrency, a cached pool grows and shrinks with demand, and the queue choice determines what happens when tasks arrive faster than they complete.
ExecutorsThreadPoolExecutorRunnableCallableFuture
2
The operational details are where interviews and production bite. A pool must be shut down explicitly — shutdown() for an orderly drain, shutdownNow() to attempt cancellation — or its non-daemon threads keep the JVM alive. Executors.newFixedThreadPool and newCachedThreadPool use an unbounded queue or unbounded thread growth respectively, so a flood of tasks can cause memory exhaustion; for production it is safer to configure a ThreadPoolExecutor with a bounded queue and a deliberate rejection policy. And exceptions thrown by tasks submitted via submit are swallowed into the Future rather than logged, so they must be retrieved or they vanish silently.
shutdown()shutdownNow()Executors.newFixedThreadPoolnewCachedThreadPoolThreadPoolExecutor