Algum tempo atrás, escrevi um post sobre interfaces Java Callable Future que podemos usar para obter os benefícios do processamento concorrente de threads, bem como são capazes de retornar valores ao programa chamador. FutureTask é uma implementação concreta base da interface Future e fornece processamento assíncrono. Ele contém métodos para iniciar e cancelar uma tarefa e também métodos que podem retornar o estado do FutureTask, seja concluído ou cancelado. Precisamos de um objeto chamável para criar uma tarefa futura e então podemos usar Executor de Pool de Threads Java para processá-las de forma assíncrona. Vamos ver o exemplo de FutureTask com um programa simples. Como FutureTask requer um objeto chamável, 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);
//retorna o nome da thread que executa esta tarefa chamável
return Thread.currentThread().getName();
}
}
Aqui está um exemplo do método FutureTask e ele está mostrando métodos comumente usados do 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ê notará que ele não imprime nada por um tempo porque o método get()
do 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 uma quantidade específica de tempo, e estamos usando-o para o 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
Portanto, não há benefício direto do FutureTask, mas é útil quando queremos substituir alguns 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