junior
Structured Concurrency — что это и зачем?
Structured Concurrency — API для управления группами связанных задач как единым целым. Гарантирует, что подзадачи завершатся (или будут отменены) до завершения родительской задачи, предотвращая утечки потоков.
Аналогия из жизни: как руководитель проекта, который не уходит домой, пока все члены команды не сдали свои части работы. Если один провалил задачу — остальным сообщают, что проект отменён, и они тоже прекращают работу.
Пример: ShutdownOnFailure и ShutdownOnSuccess
// Проблема: без Structured Concurrency
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
Future<User> userFuture = executor.submit(() -> fetchUser(id));
Future<List<Order>> ordersFuture = executor.submit(() -> fetchOrders(id));
// Если fetchOrders бросит исключение — fetchUser продолжает выполняться!
// Если основной поток прервётся — подзадачи «утекают»
// Решение: Structured Concurrency
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Subtask<User> user = scope.fork(() -> fetchUser(id));
Subtask<List<Order>> orders = scope.fork(() -> fetchOrders(id));
scope.join(); // ждём завершения обеих задач
scope.throwIfFailed(); // бросить исключение, если одна из задач упала
return new UserWithOrders(user.get(), orders.get());
}
// При ошибке одной задачи — другая отменяется автоматически
// ShutdownOnSuccess — вернуть первый успешный результат
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> fetchFromPrimary());
scope.fork(() -> fetchFromFallback());
scope.join();
return scope.result(); // первый успешный
}
Стратегии
| Стратегия | Поведение | Когда использовать |
|---|---|---|
ShutdownOnFailure |
Отменить все при первой ошибке | Параллельные зависимые запросы |
ShutdownOnSuccess |
Вернуть первый успешный результат | Racing, fallback |
Частые ошибки
- Не вызывать
join()— безjoin()результаты недоступны и подзадачи могут утечь - Использовать вне try-with-resources — scope должен быть закрыт для гарантии завершения
- Путать с
CompletableFuture.allOf()— Structured Concurrency проще и безопаснее для fork-join паттерна
Как используется в 2026
- Structured Concurrency финализирован и активно используется с Virtual Threads
- Заменяет ручное управление
Future+ExecutorServiceдля параллельных запросов - В Spring-приложениях — для параллельного вызова нескольких микросервисов
На собеседовании: объясните проблему (утечка подзадач при ошибке или отмене), решение (жизненный цикл подзадач привязан к scope), и две стратегии. Частая ошибка — не понимать, зачем нужен try-with-resources для scope.