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
- 🎯 Шпаргалка для співбесіди — ключові тези, часті питання, червоні прапорці, пов’язані теми