Envio de Tarefas: Runnable versus Callable
Envie tarefas Runnable e Callable e recupere os resultados por meio de Future.
Envio de Tarefas: Runnable versus Callable é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.
Executável versus chamável
Duas interfaces funcionais representam tarefas enviadas ao ExecutorService:
- Executável: não retorna um valor e não pode declarar exceções verificadas
- Chamável<V>: retorna um resultado do tipo V e pode lançar exceções verificadas
import java.util.concurrent.*;
// Runnable — no return value
Runnable r = () -> System.out.println("Running");
// Callable<Integer> — returns a value
Callable<Integer> c = () -> {
return 42; // or do computation
};submit(Executável)
submit(Runnable) retorna um Future<?>. Chamar get() nele retorna nulo, mas confirma que a tarefa foi concluída, ou lança uma exceção se ela tiver falhado.
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<?> future = pool.submit(() ->
System.out.println("Task done on " + Thread.currentThread().getName())
);
future.get(); // waits for completion; returns null
System.out.println("Task confirmed complete");
pool.shutdown();submit(Chamável<V>)
submit(Callable) retorna um Future<V>. Chame future.get() para recuperar o resultado; a chamada bloqueia até a conclusão.
ExecutorService pool = Executors.newFixedThreadPool(2);
Callable<Integer> sumTask = () -> {
int sum = 0;
for (int i = 1; i <= 100; i++) sum += i;
return sum;
};
Future<Integer> future = pool.submit(sumTask);
Integer result = future.get(); // blocks until done
System.out.println("Sum 1..100 = " + result); // 5050
pool.shutdown();Envio de vários chamáveis com invokeAll
invokeAll() envia uma coleção de chamáveis e retorna uma lista de futuros; todos são concluídos antes do retorno:
List<Callable<String>> tasks = List.of(
() -> "Result A",
() -> "Result B",
() -> "Result C"
);
ExecutorService pool = Executors.newFixedThreadPool(3);
List<Future<String>> futures = pool.invokeAll(tasks);
for (Future<String> f : futures) {
System.out.println(f.get());
}
pool.shutdown();invokeAny: primeiro resultado bem-sucedido
invokeAny() envia uma coleção de chamáveis e retorna o resultado do primeiro que for concluído com sucesso, cancelando os demais:
List<Callable<String>> candidates = List.of(
() -> { Thread.sleep(200); return "Slow"; },
() -> { Thread.sleep(50); return "Fast"; },
() -> { Thread.sleep(100); return "Medium"; }
);
ExecutorService pool = Executors.newFixedThreadPool(3);
String winner = pool.invokeAny(candidates);
System.out.println("First: " + winner); // Fast
pool.shutdown();execute() versus submit()
execute(Runnable) dispara a tarefa e não acompanha o resultado: nenhum Future é retornado, e as exceções são perdidas, a menos que você adicione um manipulador de exceções não capturadas. submit() encapsula a tarefa em um Future, capturando as exceções para recuperação por meio de get().
ExecutorService pool = Executors.newFixedThreadPool(2);
// execute: exception silently lost
pool.execute(() -> { throw new RuntimeException("Oops!"); });
// submit: exception captured in Future
Future<?> f = pool.submit(() -> { throw new RuntimeException("Oops!"); });
try {
f.get();
} catch (ExecutionException e) {
System.out.println("Caught: " + e.getCause().getMessage());
}
pool.shutdown();Chamável com exceções verificadas
Ao contrário do executável, o chamável pode lançar exceções verificadas, o que o torna adequado para operações de E/S e de banco de dados:
Callable<String> dbQuery = () -> {
// This compiles fine — checked exception is declared on Callable.call()
if (Math.random() < 0.5) throw new java.sql.SQLException("DB error");
return "row data";
};
Future<String> f = pool.submit(dbQuery);
try {
String data = f.get();
} catch (ExecutionException e) {
if (e.getCause() instanceof java.sql.SQLException) {
System.out.println("DB failed: " + e.getCause().getMessage());
}
}Paralelização de computações independentes
Use vários envios de chamáveis para executar computações independentes em paralelo:
ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Long> sumFuture = pool.submit(() -> LongStream.rangeClosed(1,1_000_000).sum());
Future<Long> prodFuture = pool.submit(() -> LongStream.rangeClosed(1,20).reduce(1L, (a,b)->a*b));
long sum = sumFuture.get();
long prod = prodFuture.get();
System.out.println("Sum: " + sum + ", 20!: " + prod);
pool.shutdown();Agregação de resultados de chamáveis
Envie muitas tarefas e agregue os resultados quando todas estiverem concluídas:
int N = 8;
ExecutorService pool = Executors.newFixedThreadPool(N);
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < N; i++) {
final int chunk = i;
futures.add(pool.submit(() -> chunk * chunk)); // i^2
}
int total = 0;
for (Future<Integer> f : futures) total += f.get();
System.out.println("Sum of squares: " + total);
pool.shutdown();Tempo limite para um chamável
Informe um tempo limite a future.get(timeout, unit) para evitar esperar indefinidamente:
Future<String> f = pool.submit(() -> {
Thread.sleep(5000); // slow task
return "done";
});
try {
String result = f.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Task timed out");
f.cancel(true); // interrupt the task
} catch (ExecutionException e) {
System.out.println("Task failed: " + e.getCause());
}Práticas recomendadas
Resumo das práticas recomendadas:
- Prefira
submit()aexecute(): as exceções são capturadas - Use um chamável quando precisar de um valor de retorno ou de exceções verificadas
- Sempre chame
future.get()com um tempo limite - Use invokeAll para processamento em lote e invokeAny quando o primeiro resultado deve prevalecer
- Sempre encerre o pool
Verificação rápida
Qual é a principal vantagem de um chamável em relação a um executável?
Recapitulação: executável versus chamável
Principais conclusões:
- Executável: void, sem exceções verificadas; submit retorna Future<?> nulo
- Chamável: retorna V e pode lançar exceções verificadas; submit retorna Future<V>
- invokeAll: envia um lote e espera todas as tarefas terminarem
- invokeAny: retorna o primeiro resultado bem-sucedido e cancela os demais
- Sempre use submit() para capturar exceções
Perguntas Frequentes
A aula “Envio de Tarefas: Runnable versus Callable” é grátis?
Sim — o texto completo de “Envio de Tarefas: Runnable versus Callable” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.
O que vou aprender em “Envio de Tarefas: Runnable versus Callable”?
Envie tarefas Runnable e Callable e recupere os resultados por meio de Future. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Java Academy?
Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Envio de Tarefas: Runnable versus Callable”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Java Academy?
Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- ExecutorService e Tipos de Pools de Threads
- Envio de Tarefas: Runnable versus Callable
- Future e Tratamento de Erros
- ScheduledExecutorService para Tarefas Recorrentes