Introducción a la programación asíncrona en Java
Las aplicaciones modernas requieren alto rendimiento y capacidad de respuesta. La programación asíncrona en Java es un enfoque que permite ejecutar operaciones largas (por ejemplo, consultas a bases de datos, llamadas a API, lectura de archivos) sin bloquear el hilo principal de ejecución. En lugar de esperar a que finalice una tarea, el programa continúa funcionando y el resultado se procesa cuando está listo.
En esta guía, analizaremos los conceptos principales de la programación asíncrona en Java, comenzando con las herramientas básicas y terminando con la API moderna CompletableFuture. Aprenderá a crear código no bloqueante, manejar errores y combinar tareas asíncronas.
Conceptos principales: hilos y ExecutorService
Hilos (Threads)
La forma más sencilla de ejecutar código de forma asíncrona en Java es crear un nuevo hilo. Sin embargo, crear hilos manualmente es una operación costosa y, con una gran cantidad de tareas, puede provocar problemas de rendimiento.
// Ejemplo de creación de un hiloThread thread = new Thread(() -> { System.out.println("Tarea asíncrona ejecutándose en el hilo: " + Thread.currentThread().getName());});thread.start();System.out.println("El hilo principal continúa trabajando");ExecutorService — gestión del pool de hilos
Para una gestión eficiente de los hilos, Java proporciona ExecutorService. Esta es una interfaz que permite crear pools de hilos, reutilizarlos y controlar la ejecución de tareas.
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;
public class ExecutorServiceExample { public static void main(String[] args) { // Creamos un pool de 4 hilos ExecutorService executor = Executors.newFixedThreadPool(4); // Enviamos una tarea para ejecución executor.submit(() -> { System.out.println("Tarea ejecutándose en el pool de hilos"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Tarea completada"); }); // Finalizamos el trabajo del pool executor.shutdown(); }}Tipos principales de pools de hilos:
newFixedThreadPool(n)— número fijo de hilos.newCachedThreadPool()— número dinámico de hilos.newSingleThreadExecutor()— un solo hilo para ejecución secuencial de tareas.newScheduledThreadPool(n)— para programar tareas con retardo.
Future y CompletableFuture
Interfaz Future
Future es una interfaz que representa el resultado de una operación asíncrona. Permite verificar si la tarea ha finalizado, esperar a que termine y obtener el 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("Esperando el resultado..."); Integer result = future.get(); // Bloquea el hilo hasta obtener el resultado System.out.println("Resultado: " + result); executor.shutdown(); }}La desventaja de Future es que el método get() bloquea el hilo. Para un trabajo más flexible con tareas asíncronas, se creó CompletableFuture.
CompletableFuture — una potente herramienta de asincronía
CompletableFuture