Skip to content
Ameen Abozaid
MID-006

Async programming

  • 6 Lessons
  • 3 h practice (estimate)
On this page 8 topics

Overview

Topics

  • CompletableFuture
  • composition
  • exception propagation
  • cancellation

Learn first

3 h of practice (estimate)

Learning outcomes

  1. Compose asynchronous work with CompletableFuture (thenApply, thenCompose, thenCombine, allOf).
  2. Propagate and handle exceptions in async chains.
  3. Apply timeouts and cancellation.
  4. Choose the executor for async stages deliberately.

Lessons

  1. 01Futures vs CompletableFuture
  2. 02Composing stages
  3. 03Errors in async code
  4. 04Timeouts and cancellation
  5. 05Which thread runs my stage?
  6. 06Demo: fan-out to three services with a deadline

Lab and exercises

Lab

MID-006-LAB1 · Product page aggregator

Outcomes: 1–4 · Time: ~3 h Fetch product, stock, and reviews concurrently from simulated services on a dedicated executor. Apply an overall deadline and per-call timeouts. On failure return partial results with a degraded marker. Acceptance: total latency about equal to the slowest call; failures degrade gracefully.

Exercises (assessment: fix a broken async chain)

IDOutcomeTask
MID-006-EX011Combine two independent price lookups with thenCombine, then fetch the seller using the result with thenCompose.
MID-006-EX021Wait for ten futures with allOf and collect the results into a list.
MID-006-EX032Given a chain that swallows an exception, fix it so the error is handled and logged with a fallback.
MID-006-EX043Add a 200 ms default-on-timeout to a slow call and show the default arriving.
MID-006-EX054Fix a chain that runs blocking HTTP calls on the common pool by passing an executor.
MID-006-EX062Explain CompletionException vs ExecutionException and unwrap the real cause.
Show solutions
  • EX01 a.thenCombine(b, Math::min).thenCompose(p -> sellerFor(p)).
  • EX02 CompletableFuture.allOf(arr).thenApply(v -> futures.stream().map(CompletableFuture::join).toList()); join is safe here because all are complete.
  • EX03 Replace an empty catch or an unread future with .handle((v, ex) -> { if (ex != null) { log.warn(...); return fallback; } return v; }).
  • EX04 slow.completeOnTimeout(DEFAULT, 200, MILLISECONDS).
  • EX05 CompletableFuture.supplyAsync(() -> http.call(), ioPool).
  • EX06 join() throws CompletionException and get() throws ExecutionException; both wrap the original in getCause().

Quiz

Outcomes: O1 composing stages · O2 errors · O3 timeouts and cancellation · O4 executors.

A self-check for you: nothing is graded, saved or sent anywhere. Choose an answer, then check it. You can try again as often as you like.

  1. 1For a dependent async call (B needs A's result) use:O1
  2. 2For two independent futures joined into one value use:O1
  3. 3CompletableFuture.allOf(...) returns:O1
  4. 4To recover from a failure with a default:O2
  5. 5If a stage fails, a later thenApply stage is:O2
  6. 6join() throws:O2
  7. 7completeOnTimeout(v, 300, MILLISECONDS) does:O3
  8. 8cancel(true) on a CompletableFuture:O3
  9. 9The default pool for supplyAsync without an executor is:O4
  10. 10Blocking I/O in async stages should use:O4

Practical part

Six exercises MID-006-EX01 to EX06 including fixing a broken async chain, plus the lab. Pass: at least five exercises correct and the lab showing latency near the slowest call with graceful degradation.

Common mistakes

Blocking join() inside stages; losing exceptions; using the common pool for blocking I/O.

Assessment

Fix a broken async chain.

Career relevance

Resilience patterns (MID-033).

Type to search levels, phases, modules and lessons.