Cuando tu código empieza a tartamudear: introducción a las colas y tareas en segundo plano en Java
\n\nImagine la situación: inicia un servidor web en Java. Llega una solicitud de un usuario: hay que enviar un correo, generar un informe PDF y actualizar las estadísticas. Si se hace todo de forma síncrona, el usuario esperará 30 segundos. Su café se enfriará y se irá con la competencia. ¿Le suena familiar?
\n\nEn el mundo de las tareas en segundo plano en Java, esto se resuelve de forma elegante: lanzamos la tarea a una cola y devolvemos al usuario un «200 OK». Luego, en segundo plano, nuestro trabajador procesa tranquilamente los correos, PDFs y estadísticas. Sin caos, solo orden.
\n\nHoy analizaremos cómo implementar colas de tareas en Java, desde la opción monohilo más simple hasta soluciones industriales con RabbitMQ y Kafka. Aprenderá a dejar de apagar incendios y empezar a diseñar sistemas fiables.
\n\n¿Para qué sirven las colas? Tres razones que le sorprenderán
\n\n- \n
- Asincronía — el usuario no espera. La velocidad de respuesta del servidor cae de 30 segundos a 5 milisegundos. \n
- Equilibrio de carga — los picos de solicitudes no tumban el servidor. Las tareas se almacenan en la cola y se procesan a medida que se liberan recursos. \n
- Tolerancia a fallos — si un trabajador falla, la tarea permanece en la cola. Otro trabajador la retomará. Los datos no se pierden. \n
En Java existen herramientas integradas (ExecutorService, BlockingQueue) y brokers externos (RabbitMQ, Kafka). La elección depende de la escala. Empecemos por lo pequeño.
Cola simple en Java: ExecutorService y BlockingQueue
\n\nSi no necesita un sistema distribuido, sino simplemente sacar el trabajo pesado a segundo plano, use ThreadPoolExecutor. Es un grupo de hilos integrado que toma tareas de una cola.
Ejemplo: grupo de hilos para procesar pedidos
\n\nimport java.util.concurrent.*;\n\npublic class OrderProcessor {\n private final ExecutorService executor;\n\n public OrderProcessor(int threadCount) {\n // Creamos un grupo con un número fijo de hilos\n this.executor = Executors.newFixedThreadPool(threadCount);\n }\n\n public void processOrder(Order order) {\n executor.submit(() -> {\n // Trabajo pesado: generar recibo, enviar email, actualizar inventario\n System.out.println("Procesando pedido: " + order.getId());\n try {\n Thread.sleep(2000); // simulación de trabajo\n } catch (InterruptedException e) {\n Thread.currentThread().interrupt();\n }\n System.out.println("Pedido " + order.getId() + " procesado");\n });\n }\n\n public void shutdown() {\n executor.shutdown();\n }\n\n public static void main(String[] args) {\n OrderProcessor processor = new OrderProcessor(4);\n for (int i = 0; i < 10; i++) {\n processor.processOrder(new Order(i));\n }\n processor.shutdown();\n }\n}\n\nclass Order {\n private final int id;\n public Order(int id) { this.id = id; }\n public int getId() { return id; }\n}\n\n¿Qué ocurre aquí? Hemos creado un grupo de 4 hilos. 10 pedidos se procesarán de 4 en 4 en paralelo. La cola de tareas en Java se gestiona internamente en ThreadPoolExecutor — por defecto es una LinkedBlockingQueue. Cuando todos los hilos están ocupados, las tareas esperan su turno.
Configuración avanzada: prioridades y tolerancia a fallos
\n\n¿Y si las tareas son urgentes? Use PriorityBlockingQueue:
BlockingQueue<Runnable> priorityQueue = new PriorityBlockingQueue<>(\n 10,\n Comparator.comparingInt(task -> ((PriorityTask) task).getPriority())\n);\n\nThreadPoolExecutor executor = new ThreadPoolExecutor(\n 2, 4, 60, TimeUnit.SECONDS, priorityQueue\n);\n\nAhora las tareas con prioridad alta