Paralelismo em Java com Callable
Pool de threads:
Na versão 5 do java, foram adicionadas classes para ajudar o desenvolvimento de threads e uma destas evoluções foram as pool d threads.Uma pool de thread nada mais é do que uma maneira de administrar a execução das threads do seu programa. Caso você tenha 10000 threads para serem executadas, se você criar todas elas na mão e mandar executar fica difícil de administrar a execução de cada uma delas, colocando todas elas em um pool de threads, você pode controlar quantas serão executadas ao mesmo tempo e a máquina virtual é quem vai administrar a execução de todas as suas threads.
E como eu defino uma pool de threads?
ExecutorService executor = Executors.newFixedThreadPool(10);No código acima, definimos uma pool de threads com tamanho fixo, existem várias outras maneiras de se definir uma pool de threads, mas aqui no nosso curso esta maneira é suficiente.
A grande vantagem de se usar pool de threads é que você pode determinar quantas threads serão executadas ao mesmo tempo no seu sistema, e a pool de threads é quem administra quem será executado e quando. Existe um cálculo que pode determinar qual é a quantidade ideal de threads de acordo com a sua máquina, mas para fazer este cálculo você tem que levar em conta o que o seu código faz. Porém, não adianta você colocar 10000 threads em uma máquina de 8 núcleos, que ela não vai conseguir executar todas as threads ao mesmo tempo, e isso provavelmente seja difícil de administrar. Já com as pool de threads, você cria, determina qual será a quantidade de threads executadas e pronto, ela administra pra você.
Estas pools, possuem métodos para receber as threads que serão executadas, como o método submit, este método retorna uma classe Future, que será explicada abaixo:
Future<Integer> futuro = executor.submit(new ExemploCallable(i));A classe future, possui um método chamado get, que quando executado, retorna o resultado do método de execução de uma thread, quando ele termina. Quando você chama o método get, ele fica esperando a thread acabar de executar. Como no nosso caso isso é imediato, não haverá nenhuma espera.
Múltiplas chamadas ao método get, não fará a thread executar várias vezes, só esperará o retorno do resultado da thread.
O método submit pode receber uma instancia de Runnable, ou de Callable. Quando passarmos uma instancia de runnable ele irá retornar nulo, ao final da execução do método, callable será explicada a seguir.
Até agora em nossos cursos trabalhamos apenas com a extensão da classe Thread ou a implementação da interface Runnable, mas e quando precisamos de um retorno do método da thread exectado, como faremos?
Interface Callable<T>
A interface Callable serve para resolver este problema, esta interface define um método call que possui um retorno e este retorno é definido pela classe T determinada na hora de implementar esta interface.public class ExemploCallable implements Callable<Integer>{A classe acima define que o ExemploCallable terá um método call retornando um Integer.
No exemplo abaixo definiremos uma maneira de implementar a soma de Fibonacci usando threads com a interface Callable<T>.
public class ExemploCallable implements Callable<Integer>{Repare que para construir a classe ExemploCallable passamos como argumento um inteiro, sendo este inteiro o índice do nosso loop for.
private Integer indice;
public ExemploCallable(int indice) {
this.indice=indice;
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
Set<Future<Integer>> set = new HashSet<Future<Integer>>();
Future<Integer> futuro =null;
for(int i=0;i<20;i++){
futuro = executor.submit(new ExemploCallable(i));
set.add(futuro);
}
int soma = 0;
try {
for (Future<Integer> resultadoFuturo : set) {
soma += resultadoFuturo.get();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("A soma índices é "+ soma);
System.exit(soma);
}
@Override
public Integer call() throws Exception {
return indice;
}
}
O método call simplesmente retorna este valor, com o retorno deste método iremos realizar a soma de todos os valores, o que nada mais é do que um Fibonacci.