Pesquisar este blog

segunda-feira, 20 de maio de 2013

Paralelismo em Java com Callable

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>{

    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;
    }
}
 Repare que para construir a classe ExemploCallable passamos como argumento um inteiro, sendo este inteiro o índice do nosso loop for.
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.

2 comentários:

  1. Oi Professor segunda vai ter a vista das provas.... p2

    ResponderExcluir
  2. Olá, tudo bem
    O plano é rever as provas nesta próxima segunda, a não ser que as manifestações atrapalhem, ai podemos marcar para outro dia, mas eu aviso.

    ResponderExcluir