Pool de Threads
Um pool de threads é uma coleção de threads disponíveis para realizar tarefas
Pools geralmente provêem:
Melhor performance quando se executam um grande número de tarefas devido a um overhead reduzido de chamadas por tarefa;
Uma forma de limitar recursos consumidos (incluindo threads) ao executar uma coleção de tarefas;
Um programa com milhares de threads pode sofrer em desempenho
Adicionalmente, com um pool de threads, você não precisa preocupar-se com o cilclo de vida dos threads (criação, destruição)
Você pode se concentrar em criar business logic em vez de gerenciar threads
Para usar pools de threads, instancie uma implementação da interface ExecutorService e entregue tarefas para execução
Duas implementações da interface:
ThreadPoolExecutor
ScheduledThreadPoolExecutor
As implementações permitem que você estabeleça:
O número básico e máximo do pool (número de threads)
O tipo de estrutura de dados para armazenar as tarefas
Como tratar tarefas rejeitadas
Como criar e terminar threads
Porém, é melhor criar pools usando od factory methods da classe Executors (ver tabela)
Os métodos acertam a configuração do pool para os casos mais típicos
Factory Methods na classe Executors
Método Descrição
newFixedThreadPool(int) Cria um pool com número fixo de threads e fila
ilimitada de tarefas
newCachedThreadPool Cria um pool de threads sem limite, com recuperação
automática de threads (threads que já terminaram as tarefas são reutilizados
para novas tarefas e novos threads são criados só se não houver thread "velho" disponível)
É uma boa opção quando há muitas tarefas pequenas a executar assincronamente.
Threads não usados por 60 segundos são removidos
newSingleThreadExecutor Cria um thread único em background com fila ilimitada de tarefas
As tarefas serão executadas sequencialmente
Abaixo está uma tarefa WorkerThread que será executada por um thread
A tarefa faz algo e periodicamente informa o percentual de trabalho realizado
public class WorkerThread implements Runnable {
private int workerNumber;
WorkerThread(int number) {
workerNumber = number;
}
public void run() {
for (int i=0;i<=100;i+=20) { // Perform some work ... System.out.println("Worker number: " + workerNumber + ", percent complete: " + i ) try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { } } } }
Em ThreadPoolTest especificamos o número de "worker threads" (tarefas) a criar e o tamanho do pool de threads usados para executar as tarefas
O exemplo usa um número fixo de threads e com menos threads do que tarefas
<code>
import java.util.concurrent.*;
public class ThreadPoolTest {
public static void main(String[] args) {
int numWorkers = Integer.parseInt(args[0]);
int threadPoolSize = Integer.parseInt(args[1]);
ExecutorService tpes =
Executors.newFixedThreadPool(threadPoolSize);
WorkerThread[] workers = new WorkerThread[numWorkers];
for (int i = 0; i < numWorkers; i++) { workers[i] = new WorkerThread(i); tpes.execute(workers[i]); } tpes.shutdown(); } }
</code>Execução do teste com 4 tarefas e um pool com 2 threads:
%
java ThreadPoolTest 4 2 Worker number:
0, percent complete: 0 Worker number: 1,
percent complete: 0 Worker number: 0,
percent complete: 20 Worker number: 0,
percent complete: 40 Worker number: 1,
percent complete: 20 Worker number: 0,
percent complete: 60 Worker number: 0,
percent complete: 80 Worker number: 0,
percent complete: 100 Worker number: 1,
percent complete: 40 Worker number: 1,
percent complete: 60 Worker number: 2,
percent complete: 0 Worker number: 1,
percent complete: 80 Worker number: 2,
percent complete: 20 Worker number: 2,
percent complete: 40 Worker number: 1,
percent complete: 100 Worker number: 2,
percent complete: 60 Worker number: 2,
percent complete: 80 Worker number: 2,
percent complete: 100 Worker number: 3,
percent complete: 0 Worker number: 3,
percent complete: 20 Worker number: 3,
percent complete: 40 Worker number: 3,
percent complete: 60 Worker number: 3,
percent complete: 80 Worker number: 3,
percent complete: 100
Observe como as tarefas 0 e 1 foram alocadas ao 2 threads e rodam até terminar
Só depois disso é que as tarefas 2 e 3 podem ser alocadas a threads e iniciar
WorkerThread implementa a interface Runnable
Também podemos implementar a interface Callable como em callableWorkerThread abaixo
Callable é mais flexível que Runnable pois pode retornar um valor lançar uma exceção
import java.util.concurrent.*;
public class CallableWorkerThread implements Callable {
private int workerNumber;
CallableWorkerThread(int number) {
workerNumber = number;
}
public Integer call() {
for (int i = 0; i <= 100; i += 20) { // Perform some work ... System.out.println("Worker number: " + workerNumber + ", percent complete: " + i ); try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { } } return(workerNumber); } }
ThreadPoolTest2 usa o executor CachedThreadPool que cria quantos threads forem necessários mas reutiliza threads quando uma tarefa termina
O método submit() pede a um executor para rodar um Callable
O método retorna um objeto do tipo Future que permite controlar a tarefa
Com o objeto Future podemos receber o resultado da tarefa, monitorar a tarefa e cancelar a tarefa
Por exemplo, para receber o valor retornado pela tarefa:
public class ThreadPoolTest2 {
public static void main(String[] args) {
int numWorkers = Integer.parseInt(args[0]);
ExecutorService tpes =
Executors.newCachedThreadPool();
CallableWorkerThread workers[] =
new CallableWorkerThread[numWorkers];
Future futures[] = new Future[numWorkers];
for (int i = 0; i < numWorkers; i++) { workers[i] = new CallableWorkerThread(i); futures[i]=tpes.submit(workers[i]); } for (int i = 0; i < numWorkers; i++) { try { System.out.println("Ending worker: " + futures[i].get()); } catch (Exception e) {} } } }
Eis o resultado
Observe como cada tarefa inicia imediatamente
Quando a tarefa termina, ela retorna seu número que é obtido através do objeto Future
% java ThreadPoolTest2 4
Worker number: 0, percent complete: 0
Worker number: 1, percent complete: 0
Worker number: 2, percent complete: 0
Worker number: 3, percent complete: 0
Worker number: 3, percent complete: 20
Worker number: 3, percent complete: 40
Worker number: 3, percent complete: 60
Worker number: 1, percent complete: 20
Worker number: 0, percent complete: 20
Worker number: 1, percent complete: 40
Worker number: 2, percent complete: 20
Worker number: 3, percent complete: 80
Worker number: 0, percent complete: 40
Worker number: 2, percent complete: 40
Worker number: 2, percent complete: 60
Worker number: 1, percent complete: 60
Worker number: 3, percent complete: 100
Worker number: 2, percent complete: 80
Worker number: 2, percent complete: 100
Worker number: 0, percent complete: 60
Worker number: 0, percent complete: 80
Worker number: 0, percent complete: 100
Worker number: 1, percent complete: 80
Ending worker: 0
Worker number: 1, percent complete: 100
Ending worker: 1
Ending worker: 2
Ending worker: 3
Comentários
Postar um comentário