Algum tempo atrás, escrevi um post sobre interfaces Java Callable Future que podemos usar para obter os benefícios de processamento concorrente de threads, além de serem capazes de retornar valores ao programa chamador. FutureTask é a implementação concreta base da interface Future e fornece processamento assíncrono. Ele contém métodos para iniciar e cancelar uma tarefa, bem como métodos que podem retornar o estado do FutureTask, seja concluído ou cancelado. Precisamos de um objeto callable para criar uma tarefa futura e então podemos usar Java Thread Pool Executor para processá-las de forma assíncrona. Vamos ver o exemplo de FutureTask com um programa simples. Como FutureTask requer um objeto callable, vamos criar uma implementação Callable simples.
package com.journaldev.threads;
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
private long waitTime;
public MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@Override
public String call() throws Exception {
Thread.sleep(waitTime);
// retornar o nome da thread executando esta tarefa callable
return Thread.currentThread().getName();
}
}
Aqui está um exemplo do método FutureTask e está mostrando os métodos comumente usados de FutureTask.
package com.journaldev.threads;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureTaskExample {
public static void main(String[] args) {
MyCallable callable1 = new MyCallable(1000);
MyCallable callable2 = new MyCallable(2000);
FutureTask futureTask1 = new FutureTask(callable1);
FutureTask futureTask2 = new FutureTask(callable2);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(futureTask1);
executor.execute(futureTask2);
while (true) {
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
// desligar o serviço executor
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
// esperar indefinidamente pela conclusão da tarefa futura
System.out.println("FutureTask1 output="+futureTask1.get());
}
System.out.println("Waiting for FutureTask2 to complete");
String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(TimeoutException e){
// não fazer nada
}
}
}
}
Quando executamos o programa acima, você perceberá que ele não imprime nada por um tempo porque o método `get()` de `FutureTask` espera que a tarefa seja concluída e depois retorna o objeto de saída. Há também um método sobrecarregado para esperar apenas por uma quantidade específica de tempo, e estamos usando-o para `futureTask2`. Observe também o uso do método `isDone()` para garantir que o programa seja encerrado assim que todas as tarefas forem executadas. A saída do programa acima será:
FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=pool-1-thread-2
Done
Não há benefício direto de `FutureTask`, mas é útil quando queremos substituir alguns dos métodos da interface `Future` e não queremos implementar todos os métodos da interface `Future`.
Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program