Разбираем запуск и композицию асинхронных вычислений с помощью
CompletableFuture: как стартовать задачи через
supplyAsync и
runAsync, чем отличаются обработчики
thenApply,
thenAccept,
thenRun, и когда выбирать их асинхронные версии
thenApplyAsync/
thenAcceptAsync/
thenRunAsync. Поговорим о потоках выполнения (
ForkJoinPool или ваш
Executor), типах результатов (
CompletableFuture<T>,
CompletableFuture<Void>) и типичных ошибках: блокирующие
get()/
join(), необработанные ошибки без
exceptionally/
handle/
whenComplete, а также попытка использовать результат внутри
thenRun.