Skip to main content

Executors & Futures

intermediate14 min readLesson 96 of 180

Submitting tasks, rethrowing ExecutionExceptions, and latch-based completion for deterministic assertions.

ExecutorService and Futures

Executors decouple task submission from thread management:

ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Integer> f = pool.submit(() -> expensive());
Integer result = f.get();      // blocks until done
pool.shutdown();               // always โ€” or the JVM won't exit

Key behaviors:

  • submit returns a Future immediately; get() joins that one task
  • tasks run on pool threads โ€” exceptions inside them do NOT crash your thread; get() rethrows them wrapped in ExecutionException
  • invokeAll submits a batch; the returned Futures complete in order
  • always shutdown() โ€” try/finally or close() (ExecutorService is AutoCloseable since Java 19)

Deterministic testing pattern: submit N tasks, get() each โ€” after all gets return, every side effect is visible. Latches are the tool when tasks must all finish before an assertion:

CountDownLatch done = new CountDownLatch(n);
// each task: work(); done.countDown();
done.await();   // wait for all n countDowns

Now practice

Concurrency LabProve the atomic fix under contention, parallel sums that rejoin deterministically, and latch-synchronized fan-out.3 challenges ยท ยท ~40 min