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

Postagens mais visitadas deste blog

E Esse Tal de Nano Service?

Executar Audio em Java Swing

Validando Email em Java Com e Sem expressão Regular