CompletableFuture и асинхронность
28 вопросов и ответов в разделе CompletableFuture и асинхронность.
Вопросы этого раздела
- Что такое CompletableFuture и чем он отличается от Future
- Какие основные преимущества CompletableFuture перед Future
- Как создать CompletableFuture, который уже завершён с результатом?
- В чём разница между thenApply() и thenCompose()
- Что делают методы thenAccept() и thenRun()
- Как обрабатывать исключения в цепочке CompletableFuture
- В чём разница между handle(), exceptionally() и whenComplete()?
- Как комбинировать результаты нескольких CompletableFuture
- Что делает метод allOf() и когда его использовать
- Что делает метод anyOf() и в каких случаях он полезен
- В чём разница между thenApply() и thenApplyAsync()
- Какой пул потоков используется по умолчанию для async методов?
- Как указать свой Executor для CompletableFuture?
- Что такое блокирующий код и как его отличить от неблокирующего
- Почему важно избегать блокирующих операций в CompletableFuture
- Как правильно выполнить несколько параллельных запросов к микросервисам
- Что делает метод supplyAsync() и когда его использовать
- Как отменить выполнение CompletableFuture
- Что произойдёт, если в цепочке CompletableFuture возникнет исключение?
- Можно ли повторно использовать один CompletableFuture в нескольких цепочках?
- Как реализовать timeout для CompletableFuture
- Что делает метод orTimeout() в Java 9+
- В чём разница между thenCombine() и thenCompose()
- Как тестировать код с CompletableFuture
- В каких случаях лучше использовать CompletableFuture, а в каких — реактивное программирование?
- Что делает метод join() и чем он отличается от get()
- Можно ли вручную завершить CompletableFuture результатом
- Как реализовать retry логику с помощью CompletableFuture
Навигатор по разделу
28 вопросов для подготовки к собеседованию на Middle/Senior Java Developer.
📋 Все вопросы
🗺️ Карта зависимостей тем
┌──────────────────────────────────────────┐
│ ОСНОВЫ (1-5) │
│ 1. CompletableFuture vs Future │
│ 2. Преимущества │
│ 3. completedFuture │
│ 4. thenApply vs thenCompose │
│ 5. thenAccept vs thenRun │
└──────────────────┬───────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌────────────────────┐
│ ИСКЛЮЧЕНИЯ │ │ КОМБИНИРОВАНИЕ │ │ EXECUTORS │
│ (6-7, 19) │ │ (8-11, 23) │ │ (12-13, 17) │
│ 6. Обработка │ │ 8. Комбинир. │ │ 12. Common Pool │
│ 7. handle/ │ │ 9. allOf │ │ 13. Custom Exec. │
│ exceptionally│ │ 10. anyOf │ │ 17. supplyAsync │
│ 19. Исключ. │ │ 11. *Async │ │ │
│ в цепочке │ │ 23. thenCombine│ │ │
└───────┬───────┘ └───────┬───────┘ └────────┬───────────┘
│ │ │
└────────────────────────┼────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ BLOCKING И TIMEOUT (14-16, 20-22) │
│ 14. Blocking vs Non-blocking │
│ 15. Почему избегать blocking │
│ 16. Параллельные запросы │
│ 20. Timeout │
│ 21. orTimeout (Java 9+) │
└──────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌────────────────────┐
│ ADVANCED │ │ TESTING │ │ PATTERNS │
│ (18, 25-28) │ │ (24) │ │ (27) │
│ 18. Cancel │ │ 24. Тестир. │ │ 27. Retry │
│ 25. join vs get│ │ │ │ │
│ 26. obtrude │ │ │ │ │
│ 25. CF vs │ │ │ │ │
│ Reactive │ │ │ │ │
└───────────────┘ └───────────────┘ └────────────────────┘
🎯 Рекомендуемый порядок изучения
🟢 Уровень Junior (недели 1-2)
| Шаг | Тема | Файлы | Цель |
|---|---|---|---|
| 1 | Основы | Q1, Q2, Q3 | Чем отличается от Future, completedFuture |
| 2 | Цепочки | Q4, Q5 | thenApply, thenCompose, thenAccept, thenRun |
| 3 | Исключения | Q6, Q7 | exceptionally, handle, whenComplete |
| 4 | join vs get | Q25 | Чем отличаются, почему join предпочтительнее |
🟡 Уровень Middle (недели 3-4)
| Шаг | Тема | Файлы | Цель |
|---|---|---|---|
| 1 | Комбинирование | Q8, Q9, Q10, Q23 | allOf, anyOf, thenCombine, thenCompose |
| 2 | Async методы | Q11, Q17 | thenApply vs thenApplyAsync, supplyAsync |
| 3 | Blocking | Q14, Q15 | Что такое blocking, почему опасен в commonPool |
| 4 | Timeout | Q20, Q21 | Ручной timeout, orTimeout (Java 9+) |
| 5 | Testing | Q24 | Awaitility, Testcontainers, Virtual Threads |
🔴 Уровень Senior (недели 5-6)
| Шаг | Тема | Файлы | Цель |
|---|---|---|---|
| 1 | Executors | Q12, Q13 | CommonPool internals, custom executors, ManagedBlocker |
| 2 | Parallel requests | Q16 | Semaphore + dedicated executor, error handling |
| 3 | Cancel & obtrude | Q18, Q26 | cancel() mechanics, obtrudeValue dangers |
| 4 | Reuse CF | Q19 | Fan-out, memory leak via reference chains |
| 5 | CF vs Reactive | Q25 | When to use each, Virtual Threads impact |
| 6 | Retry patterns | Q28 | exceptionallyCompose, exponential backoff + jitter |
🔗 Ключевые связи между темами
Тема: Основы
Q1 (CF vs Future) → Q2 (Преимущества) → Q3 (completedFuture)
Тема: Цепочки
Q4 (thenApply vs thenCompose) → Q5 (thenAccept vs thenRun) → Q23 (thenCombine vs thenCompose)
Ключевые связи:
- Q4 ↔ Q23: thenCompose = последовательно, thenCombine = параллельно
- Q5 ↔ Q4: thenAccept = Consumer (нет результата), thenRun = Runnable (нет входа)
Тема: Исключения
Q6 (Обработка) → Q7 (handle/exceptionally/whenComplete) → Q19 (Исключение в цепочке)
Тема: Комбинирование
Q8 (Комбинирование) → Q9 (allOf) → Q10 (anyOf)
Тема: Executors и Blocking
Q12 (Common Pool) → Q13 (Custom Executor) → Q14 (Blocking) → Q15 (Почему избегать)
↓
Q17 (supplyAsync) → Q16 (Параллельные запросы)
Ключевые связи:
- Q12 ↔ Q15: Blocking в commonPool → thread pool starvation
- Q13 ↔ Q16: Параллельные запросы → dedicated executor, НЕ commonPool
- Q14 ↔ Q15: Blocking vs non-blocking → почему blocking опасен
Тема: Timeout и Cancel
Q20 (Timeout) → Q21 (orTimeout)
Q18 (Cancel) → Q26 (obtrudeValue)
🎓 Шпаргалка: что знать для каждого уровня
🟢 Junior
- CompletableFuture = async результат + цепочки коллбэков
- thenApply = трансформация, thenAccept = побочный эффект, thenRun = действие без данных
- exceptionally = fallback при ошибке, handle = обработка и успеха и ошибки
- join() = blocking без checked exceptions, get() = blocking с checked exceptions
🟡 Middle
- supplyAsync по умолчанию → ForkJoinPool.commonPool()
- Blocking в commonPool → thread pool starvation для всех задач
- allOf = ждём ВСЕ, anyOf = ждём ПЕРВЫЙ
- orTimeout (Java 9+) = built-in timeout, в Java 8 — вручную через ScheduledExecutor
- exceptionallyCompose (Java 12+) = неблокирующий retry
🔴 Senior
- commonPool размер = availableProcessors - 1, меняется через System.setProperty
- ManagedBlocker уведомляет ForkJoinPool о блокирующей операции
- obtrudeValue нарушает контракт «однократного завершения» → race conditions
- CF vs Reactive: CF = single result, Reactive = streams + backpressure
- Virtual Threads (Java 21+) упрощают blocking-код → CF менее критичен
- Retry: exponential backoff + jitter предотвращает thundering herd
📝 Формат каждого файла
Каждый файл содержит:
- 🟢 Junior Level — базовое понимание, простые аналогии, примеры
- 🟡 Middle Level — внутренности, типичные ошибки, практические примеры
- 🔴 Senior Level — deep dive, edge cases, production experience, monitoring
- 🎯 Шпаргалка для интервью — ключевые тезисы, частые вопросы, красные флаги, связанные темы