Quando seu código começa a gaguejar: introdução a filas e tarefas em segundo plano em Java
\n\nImagine a situação: você inicia um servidor web em Java. Chega uma requisição de um usuário — é necessário enviar um e-mail, gerar um relatório em PDF e atualizar as estatísticas. Se tudo for executado de forma síncrona, o usuário esperará 30 segundos. O café dele esfriará, e ele irá para a concorrência. Familiar?
\n\nNo mundo das tarefas em segundo plano em Java, isso é resolvido de forma elegante: colocamos a tarefa em uma fila e retornamos "200 OK" para o usuário. Depois, em segundo plano, nosso worker processa calmamente os e-mails, PDFs e estatísticas. Nada de caos, apenas ordem.
\n\nHoje, vamos explorar como implementar filas de tarefas em Java — desde a opção mais simples de thread única até soluções industriais com RabbitMQ e Kafka. Você aprenderá a parar de apagar incêndios e começar a projetar sistemas confiáveis.
\n\nPor que usar filas? Três razões que vão te surpreender
\n\n- \n
- Assincronia — o usuário não espera. A velocidade de resposta do servidor cai de 30 segundos para 5 milissegundos. \n
- Balanceamento de carga — picos de requisições não derrubam o servidor. As tarefas são armazenadas na fila e processadas à medida que os recursos são liberados. \n
- Tolerância a falhas — se um worker falhar, a tarefa permanece na fila. Outro worker a pegará. Os dados não são perdidos. \n
Em Java, existem ferramentas embutidas (ExecutorService, BlockingQueue) e brokers externos (RabbitMQ, Kafka). A escolha depende da escala. Vamos começar pelo básico.
Fila simples em Java: ExecutorService e BlockingQueue
\n\nSe você não precisa de um sistema distribuído, mas apenas deseja mover trabalho pesado para segundo plano — use ThreadPoolExecutor. Este é um pool de threads embutido que retira tarefas de uma fila.
Exemplo: pool de threads para processamento de pedidos
\n\nimport java.util.concurrent.*;\n\npublic class OrderProcessor {\n private final ExecutorService executor;\n\n public OrderProcessor(int threadCount) {\n // Cria um pool com número fixo de threads\n this.executor = Executors.newFixedThreadPool(threadCount);\n }\n\n public void processOrder(Order order) {\n executor.submit(() -> {\n // Trabalho pesado: geração de recibo, envio de e-mail, atualização de estoque\n System.out.println("Processando pedido: " + order.getId());\n try {\n Thread.sleep(2000); // simulação de trabalho\n } catch (InterruptedException e) {\n Thread.currentThread().interrupt();\n }\n System.out.println("Pedido " + order.getId() + " processado");\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\nO que está acontecendo aqui? Criamos um pool com 4 threads. 10 pedidos serão processados 4 por vez em paralelo. A fila de tarefas em Java é gerenciada internamente pelo ThreadPoolExecutor — por padrão, é uma LinkedBlockingQueue. Quando todas as threads estão ocupadas, as tarefas aguardam na fila.
Configuração avançada: prioridades e tolerância a falhas
\n\nE se as tarefas forem 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\nAgora, tarefas com alta prioridade