Se você já mexeu com concorrência em Java, sabe o caos:
ThreadExecutorServiceFuturecallback perdido
erro que ninguém trata
👉 código espalhado 👉 difícil de manter 👉 bugs escondidos
Structured Concurrency veio pra resolver isso.
E resolve bem.
O problema da concorrência tradicional
Olha um cenário comum:
Future<User> user = executor.submit(() -> getUser());
Future<Order> order = executor.submit(() -> getOrder());
User u = user.get();
Order o = order.get();Problemas:
❌ controle espalhado
❌ se uma falhar, a outra continua
❌ cancelamento manual
❌ código difícil de entender
O conceito de Structured Concurrency
A ideia é simples:
👉 tarefas concorrentes vivem dentro de um escopo controlado
👉 tudo começa e termina junto
👉 se algo falha → cancela tudo
👉 você não perde controle
1. Primeiro exemplo com StructuredTaskScope
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<User> user = scope.fork(() -> getUser());
Future<Order> order = scope.fork(() -> getOrder());
scope.join(); // espera tudo
scope.throwIfFailed(); // se algo falhar, lança exceção
return combine(user.resultNow(), order.resultNow());
}O que aconteceu aqui?
fork()→ cria tarefas concorrentesjoin()→ espera terminarthrowIfFailed()→ garante consistênciaShutdownOnFailure→ cancela tudo se uma falhar
isso aqui é MUITO mais seguro que Future
2. Cancelamento automático (grande vantagem)
Se uma tarefa falhar:
todas as outras são canceladas automaticamente
Isso resolve um problema clássico:
case falha:
continuar rodando outras tarefas inutilmenteAgora:
falhou uma → cancela tudo3. Usando ShutdownOnSuccess (primeiro resultado ganha)
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> callApi1());
scope.fork(() -> callApi2());
return scope.join().result();
}retorna o primeiro resultado válido, cancela o resto e perfeito pra fallback de APIs
4. Exemplo real (API agregadora)
public Response getDashboard() {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var user = scope.fork(() -> userService.getUser());
var orders = scope.fork(() -> orderService.getOrders());
var balance = scope.fork(() -> financeService.getBalance());
scope.join();
scope.throwIfFailed();
return new Response(
user.resultNow(),
orders.resultNow(),
balance.resultNow()
);
}
}👉 isso aqui é código de produção real 👉 limpo 👉 seguro 👉 fácil de manter
5. Structured Concurrency + Virtual Threads
Aqui fica poderoso de verdade.
Com Virtual Threads:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> apiCall1());
scope.fork(() -> apiCall2());
scope.fork(() -> apiCall3());
scope.join();
}👉 milhares de tasks 👉 baixo custo 👉 alta performance
Erros comuns
Misturar com código legado bagunçado
Criar escopos aninhados sem necessidade
Ignorar tratamento de erro
Usar sem entender ciclo de vida
Quando usar
Use quando:
múltiplas chamadas paralelas
agregação de dados
APIs externas
tarefas independentes
Evite quando:
lógica é sequencial
tarefas dependem uma da outra
Dica de senior
Structured Concurrency não é só sintaxe nova.
👉 é controle de fluxo
Se você usar isso bem:
evita memory leak
evita thread solta
melhora debug
deixa código previsível
Comparação rápida
Antes | Agora |
|---|---|
Future | StructuredTaskScope |
Controle manual | Controle automático |
Código espalhado | Código organizado |
Difícil debug | Fácil leitura |
Conclusão
Structured Concurrency é uma das evoluções mais importantes do Java moderno.
Resolve um problema antigo de forma elegante:
✔ controle
✔ segurança
✔ legibilidade
✔ performance
Se você trabalha com backend sério, isso aqui vira padrão.
