Introdução à programação assíncrona em Java
Aplicações modernas exigem alta performance e capacidade de resposta. A programação assíncrona em Java é uma abordagem que permite executar operações longas (como consultas a bancos de dados, chamadas de API, leitura de arquivos) sem bloquear o fluxo de execução principal. Em vez de esperar a conclusão da tarefa, o programa continua funcionando e o resultado é processado quando estiver pronto.
Neste guia, abordaremos os conceitos principais da programação assíncrona em Java, começando pelas ferramentas básicas até a API moderna CompletableFuture. Você aprenderá como criar código não bloqueante, tratar erros e combinar tarefas assíncronas.
Conceitos principais: threads e ExecutorService
Threads
A maneira mais simples de executar código assíncrono em Java é criar uma nova thread. No entanto, criar threads manualmente é uma operação custosa e, com um grande número de tarefas, pode levar a problemas de performance.
// Exemplo de criação de threadThread thread = new Thread(() -> { System.out.println("Tarefa assíncrona executando na thread: " + Thread.currentThread().getName());});thread.start();System.out.println("Thread principal continua executando");ExecutorService — gerenciamento de pool de threads
Para gerenciar threads de forma eficiente, o Java fornece ExecutorService. Esta é uma interface que permite criar pools de threads, reutilizá-los e controlar a execução de tarefas.
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;
public class ExecutorServiceExample { public static void main(String[] args) { // Cria um pool de 4 threads ExecutorService executor = Executors.newFixedThreadPool(4); // Envia uma tarefa para execução executor.submit(() -> { System.out.println("Tarefa executando no pool de threads"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Tarefa concluída"); }); // Finaliza o pool executor.shutdown(); }}Principais tipos de pools de threads:
newFixedThreadPool(n)— número fixo de threads.newCachedThreadPool()— número dinâmico de threads.newSingleThreadExecutor()— uma única thread para execução sequencial de tarefas.newScheduledThreadPool(n)— para agendar tarefas com atraso.
Future e CompletableFuture
Interface Future
Future é uma interface que representa o resultado de uma operação assíncrona. Ela permite verificar se a tarefa foi concluída, aguardar sua conclusão e obter o resultado.
import java.util.concurrent.*;
public class FutureExample { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(() -> { Thread.sleep(2000); return 42; }); System.out.println("Aguardando resultado..."); Integer result = future.get(); // Bloqueia a thread até obter o resultado System.out.println("Resultado: " + result); executor.shutdown(); }}A desvantagem do Future é que o método get() bloqueia a thread. Para um trabalho mais flexível com tarefas assíncronas, foi criado o CompletableFuture.
CompletableFuture — ferramenta poderosa de assincronia
CompletableFuture<