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 possamos utilizar. O Java 5 introduziu a interface java.util.concurrent.Callable no pacote de concorrência, que é similar à interface Runnable, mas pode retornar qualquer objeto e ser capaz de lançar exceções.
Java Callable
A interface Java Callable utiliza genéricos 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.
Java Future
Java Callable tasks retornam objeto java.util.concurrent.Future. Utilizando 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 seja bloqueada por um tempo mais longo. Existem os métodos isDone() e isCancelled() para verificar o status atual da tarefa Callable associada. Aqui está um exemplo simples de uma tarefa Callable em Java que retorna o nome da thread que executa a tarefa após um segundo. Estamos utilizando o framework Executor para executar 100 tarefas em paralelo e utilizando o Java Future para obter o resultado das tarefas enviadas.
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 que executa essa tarefa invocável
return Thread.currentThread().getName();
}
public static void main(String args[]){
//Obter ExecutorService da classe utilitária Executors, tamanho do pool de threads é 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//criar uma lista para conter o objeto Future associado ao Callable
List> list = new ArrayList>();
//Criar 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 do executor agora
executor.shutdown();
}
}
Ao executarmos o programa acima, você notará o atraso na saída porque o método get() do Java Future espera a tarefa Callable do Java ser concluída. Também observe 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 essa classe.
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example