Exemplo de Java Callable Future

Java Callable e Future são muito utilizados na programação multithreaded. Nos últimos posts, aprendemos muito sobre threads em Java, mas às vezes desejamos que uma thread possa retornar algum valor que podemos usar. O Java 5 introduziu a interface java.util.concurrent.Callable no pacote de concorrência, que é semelhante à interface Runnable, mas pode retornar qualquer objeto e ser capaz de lançar exceções.

O Java Callable

A interface Java Callable usa generics para definir o tipo de retorno do objeto. A classe Executors fornece métodos úteis para executar Java Callable em um pool de threads. Como as tarefas callable são executadas em paralelo, temos que esperar pelo objeto retornado.

O Java Future

Java Callable tasks retornam um objeto java.util.concurrent.Future. Usando o objeto Java Future, podemos verificar o status da tarefa Callable e obter o objeto retornado. Ele fornece o método get(), que pode esperar a conclusão da tarefa Callable e, em seguida, retornar o resultado. Java Future oferece o método cancel() para cancelar a tarefa Callable associada. Existe uma versão sobrecarregada do método get() onde podemos especificar o tempo de espera pelo resultado, sendo útil para evitar que a thread atual fique bloqueada por um longo tempo. Existem os métodos isDone() e isCancelled() para verificar o status atual da tarefa Callable associada. Aqui está um exemplo simples de uma tarefa Java Callable que retorna o nome da thread que está executando a tarefa após um segundo. Estamos utilizando o Executor framework para executar 100 tarefas em paralelo e usando o Java Future para obter o resultado das tarefas submetidas.

package com.journaldev.threads;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyCallable implements Callable {

    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        //retornar o nome da thread executando esta tarefa chamável
        return Thread.currentThread().getName();
    }
    
    public static void main(String args[]){
        //Obter ExecutorService da classe utilitária Executors, o tamanho do pool de threads é 10
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //criar uma lista para armazenar o objeto Future associado ao Callable
        List> list = new ArrayList>();
        //Criar uma instância de MyCallable
        Callable callable = new MyCallable();
        for(int i=0; i< 100; i++){
            //enviar tarefas Callable para serem executadas pelo pool de threads
            Future future = executor.submit(callable);
            //adicionar Future à lista, podemos obter o valor de retorno usando Future
            list.add(future);
        }
        for(Future fut : list){
            try {
                //imprimir o valor de retorno do Future, observe o atraso na saída no console
                //porque Future.get() espera a tarefa ser concluída
                System.out.println(new Date()+ "::"+fut.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //desligar o serviço executor agora
        executor.shutdown();
    }

}

Depois de executarmos o programa acima, você notará o atraso na saída porque o método get() do Java Future espera que a tarefa chamável do Java seja concluída. Observe também que apenas 10 threads estão executando essas tarefas. Aqui está um trecho da saída do programa acima.

Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...

Dica: E se quisermos substituir alguns dos métodos da interface Java Future, por exemplo, substituir o método get() para expirar após algum tempo padrão em vez de esperar indefinidamente, nesse caso a classe Java FutureTask é útil, que é a implementação base da interface Future. Confira Exemplo de Java FutureTask para aprender mais sobre esta classe.

Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example