Future.get()

public void serve() throws InterruptedException, ExecutionException, TimeoutException { final Future<Response> responseFuture = asyncCode(); final Response response = responseFuture.get(1, SECONDS); send(response); } private void send(Response response) { //... }

get()

CompletableFuture

Future

you control how tasks are submitted to ExecutorService : just use CompletableFuture.supplyAsync(..., executorService) instead of executorService.submit(...)

: just use instead of you deal with callback-based API: use promises

Future<T>

CompletableFuture

public void serve() throws InterruptedException, ExecutionException, TimeoutException { final CompletableFuture<Response> responseFuture = asyncCode(); final Response response = responseFuture.get(1, SECONDS); send(response); }

public void serve() { final CompletableFuture<Response> responseFuture = asyncCode(); responseFuture.thenAccept(this::send); }

serve()

this::send

responseFuture

send()

thenAcceptAsync(this::send, sendPool)

serve()

responseFuture

final CompletableFuture<Response> responseFuture = asyncCode(); responseFuture.exceptionally(throwable -> { log.error("Unrecoverable error", throwable); return null; }); responseFuture.thenAccept(this::send);

exceptionally()

exceptionally()

thenAccept()

send()

null

exceptionally()

final CompletableFuture<Response> responseFuture = asyncCode(); responseFuture .exceptionally(throwable -> { log.error("Unrecoverable error", throwable); return null; }) .thenAccept(this::send); //probably not what you think

Future

TimeoutException

public static <T> CompletableFuture<T> failAfter(Duration duration) { final CompletableFuture<T> promise = new CompletableFuture<>(); scheduler.schedule(() -> { final TimeoutException ex = new TimeoutException("Timeout after " + duration); return promise.completeExceptionally(ex); }, duration.toMillis(), MILLISECONDS); return promise; } private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 1, new ThreadFactoryBuilder() .setDaemon(true) .setNameFormat("failAfter-%d") .build());

TimeoutException

java.time.Duration

get()

TimeoutException

ExecutionException

TimeoutException

scheduler

failAfter()

responseFuture

final CompletableFuture<Response> responseFuture = asyncCode(); final CompletableFuture<Response> oneSecondTimeout = failAfter(Duration.ofSeconds(1)); responseFuture .acceptEither(oneSecondTimeout, this::send) .exceptionally(throwable -> { log.error("Problem", throwable); return null; });

responseFuture

oneSecondTimeout

acceptEither

responseFuture

oneSecondTimeout

asyncCode()

this::send

oneSecondTimeout

asyncCode()

oneSecondTimeout

exceptionally

this::send

send()

exceptionally

send()

within()

CompletableFuture

public static <T> CompletableFuture<T> within(CompletableFuture<T> future, Duration duration) { final CompletableFuture<T> timeout = failAfter(duration); return future.applyToEither(timeout, Function.identity()); }

final CompletableFuture<Response> responseFuture = within( asyncCode(), Duration.ofSeconds(1)); responseFuture .thenAccept(this::send) .exceptionally(throwable -> { log.error("Unrecoverable error", throwable); return null; });