skip to content

CompletableFuture

Composing asynchronous work into pipelines: creating stages, chaining and combining them, handling failures, and choosing which executor runs each callback. It is the standard async API in modern Java services, so expect to build a small pipeline out loud.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

page 2 of 2

What are the typing and design trade-offs of CompletableFuture.anyOf, and when would you reach for it?

level: principalimportance: should knowfreq 40%

basics

~20 s

anyOf completes as soon as the first of many futures finishes, returning that result. Because the inputs may differ in type, its result type is Object, so you usually cast or restrict inputs to one type.

open as a page

On which thread does a CompletableFuture exception-handling callback run, and what subtle bugs arise from that plus from where you place handle/whenComplete in the chain?

level: principalimportance: should knowfreq 30%

basics

~20 s

A non-async callback runs on whichever thread completed the stage (often a shared pool thread), so heavy or blocking work there can starve the pool. Where you put handle/whenComplete also matters: it only sees failures from stages above it, not below.

open as a page

An I/O-heavy service uses CompletableFuture.supplyAsync without an explicit executor and sees throughput cap far below expectations. Diagnose how common-pool sizing limits parallelism and what you'd change.

level: principalimportance: should knowfreq 38%

basics

~20 s

The default common pool has only about (cores − 1) threads, so at most that many blocking I/O calls run at once — adding more tasks just queues them. For I/O-bound work you want many more threads than cores, so supply a dedicated, larger (bounded) executor, or use virtual threads.

open as a page

How would you design a clean, composable async pipeline with CompletableFuture transforms, and what pitfalls do you guard against at scale?

level: principalimportance: should knowfreq 35%

basics

~20 s

Build pipelines from small, pure transform steps: thenApply for mapping, thenCompose for chaining async calls, and explicit executors for blocking work. Always attach error handling, avoid nested futures, and never block inside a callback on a shared pool.

open as a page

What are the exact semantics of cancel() on a CompletableFuture, and what do obtrudeValue/obtrudeException do that you should rarely need?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

cancel() on a CompletableFuture doesn't interrupt any thread — it just completes the future with a CancellationException; the mayInterruptIfRunning flag is ignored. obtrudeValue/obtrudeException forcibly overwrite an already-settled result, breaking the normal write-once rule — only for tests/recovery.

open as a page

showing 31–35 of 35