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