Ejemplo de programa Java FutureTask

Hace algún tiempo escribí una publicación sobre interfaces Java Callable Future que podemos utilizar para obtener los beneficios del procesamiento concurrente de hilos, además de ser capaces de devolver un valor al programa que realiza la llamada. FutureTask es una implementación concreta base de la interfaz Future y proporciona procesamiento asíncrono. Contiene métodos para iniciar y cancelar una tarea, así como métodos que pueden devolver el estado de FutureTask, ya sea que esté completada o cancelada. Necesitamos un objeto callable para crear una tarea futura y luego podemos utilizar Java Thread Pool Executor para procesarlas de forma asíncrona. Veamos el ejemplo de FutureTask con un programa simple. Dado que FutureTask requiere un objeto callable, crearemos una implementación callable simple.

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);
        //devolver el nombre del hilo que ejecuta esta tarea callable
        return Thread.currentThread().getName();
	}

}

Aquí tienes un ejemplo del método FutureTask y muestra los métodos comúnmente utilizados 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");
					//apagar el servicio del ejecutor
					executor.shutdown();
					return;
				}
				
				if(!futureTask1.isDone()){
				//esperar indefinidamente a que se complete la tarea 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){
				//no hacer nada
			}
		}
		
	}

}

Cuando ejecutamos el programa anterior, notarás que no imprime nada durante un tiempo porque el método `get()` de `FutureTask` espera a que la tarea se complete y luego devuelve el objeto de salida. También hay un método sobrecargado para esperar solo una cantidad especificada de tiempo, y lo estamos utilizando para `futureTask2`. También observa el uso del método `isDone()` para asegurarse de que el programa se termine una vez que se ejecuten todas las tareas. La salida del programa anterior 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

Por lo tanto, no hay beneficio de `FutureTask` como tal, pero resulta útil cuando queremos anular algunos métodos de la interfaz `Future` y no queremos implementar cada método de la interfaz `Future`.

Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program