Filas de Tarefas em Java: ExecutorService e ThreadPoolExecutor
Em aplicações multithread em Java, o gerenciamento de tarefas e sua execução é uma das principais tarefas. Em vez de criar uma nova thread para cada tarefa (o que é caro e ineficiente), os desenvolvedores usam filas de tarefas (Task Queues) em combinação com pools de threads. Isso permite controlar o número de threads em execução simultânea, reutilizá-las e lidar suavemente com picos de carga.
A base para trabalhar com filas de tarefas em Java é o framework java.util.concurrent, introduzido no Java 5. Os principais componentes são: ExecutorService, ThreadPoolExecutor e várias implementações de BlockingQueue.
1. ExecutorService — Interface de alto nível
ExecutorService é uma interface que fornece métodos para execução assíncrona de tarefas. Ela oculta os detalhes do gerenciamento de threads. A maneira mais popular de obter uma instância é usar os métodos de fábrica da classe Executors:
ExecutorService executor = Executors.newFixedThreadPool(4); // pool de 4 threadsexecutor.submit(() -> { System.out.println("Tarefa executando na thread: " + Thread.currentThread().getName());});executor.shutdown(); // finaliza após a execução de todas as tarefasNo entanto, os métodos de fábrica têm capacidades de configuração limitadas. Para ajustes finos, usa-se ThreadPoolExecutor diretamente.
2. ThreadPoolExecutor — Pool de threads configurável
ThreadPoolExecutor é o núcleo do framework. Ele aceita uma fila de tarefas, política de saturação, tempo de vida das threads e outros parâmetros. O construtor completo:
public ThreadPoolExecutor( int corePoolSize, // número mínimo de threads int maximumPoolSize, // número máximo de threads long keepAliveTime, // tempo de inatividade da thread antes da remoção TimeUnit unit, // unidade de tempo BlockingQueue<Runnable> workQueue, // fila de tarefas RejectedExecutionHandler handler // política para quando a fila está cheia);Exemplo de criação de um pool com fila personalizada:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 30, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() // padrão — lança exceção);executor.execute(() -> { // tarefa pesada});executor.shutdown();3. BlockingQueue — Base da fila de tarefas
O tipo de fila determina como as tarefas serão armazenadas e transmitidas às threads. As implementações mais populares:
LinkedBlockingQueue— fila ilimitada baseada em lista encadeada. Se a capacidade não for definida, pode causar estouro de memória.ArrayBlockingQueue— fila limitada baseada em array. Permite controlar o número de tarefas em espera.SynchronousQueue— fila de capacidade zero. Cada tarefa é passada diretamente para uma thread, sem espera na fila.PriorityBlockingQueue— fila com prioridades. As tarefas são ordenadas por prioridade (implementamComparable).
Exemplo com fila limitada e política de rejeição:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 5, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy() // tarefa executada na thread chamadora);for (int i = 0; i < 20; i++) { executor.submit(() -> { Thread.sleep(100); return Math.random(); });}executor.shutdown();4. Políticas de saturação (RejectedExecutionHandler)
Quando a fila está ch
Também na biblioteca
Valgrind para C++: guia completo com exemplos práticos
NodaTime para C# (.NET): guia completo com exemplos práticos
Processamento JSON em Rust: serde_json, simd-json, json5 e outras bibliotecas