Ejemplo de Java Callable Future

Java Callable y Future se utilizan mucho en programación multiproceso. En las últimas publicaciones, aprendimos mucho sobre hilos de Java, pero a veces deseamos que un hilo pueda devolver algún valor que podamos usar. Java 5 introdujo la interfaz java.util.concurrent.Callable en el paquete de concurrencia, que es similar a la interfaz Runnable pero puede devolver cualquier objeto y lanzar excepciones.

Java Callable

La interfaz Java Callable utiliza genéricos para definir el tipo de retorno del objeto. La clase Executors proporciona métodos útiles para ejecutar Java Callable en un grupo de hilos. Dado que las tareas callable se ejecutan en paralelo, debemos esperar el objeto devuelto.

Java Future

Java Callable tasks devuelve un objeto java.util.concurrent.Future. Utilizando el objeto Java Future, podemos conocer el estado de la tarea Callable y obtener el objeto devuelto. Proporciona el método get(), que puede esperar a que Callable finalice y luego devolver el resultado. Java Future ofrece el método cancel() para cancelar la tarea Callable asociada. Hay una versión sobrecargada del método get() donde podemos especificar el tiempo de espera para el resultado; es útil para evitar que el hilo actual se bloquee durante más tiempo. Existen los métodos isDone() e isCancelled() para conocer el estado actual de la tarea Callable asociada. Aquí tienes un ejemplo sencillo de una tarea Callable en Java que devuelve el nombre del hilo que ejecuta la tarea después de un segundo. Estamos utilizando el framework Executor para ejecutar 100 tareas en paralelo y utilizando Java Future para obtener el resultado de las tareas 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);
        //devuelve el nombre del hilo que ejecuta esta tarea invocable
        return Thread.currentThread().getName();
    }
    
    public static void main(String args[]){
        //Obtener ExecutorService desde la clase de utilidad Executors, el tamaño del grupo de hilos es 10
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //crear una lista para contener el objeto Future asociado con Callable
        List> list = new ArrayList>();
        //Crear una instancia de MyCallable
        Callable callable = new MyCallable();
        for(int i=0; i< 100; i++){
            //enviar tareas Callable para que sean ejecutadas por el grupo de hilos
            Future future = executor.submit(callable);
            //agregar Future a la lista, podemos obtener el valor de retorno usando Future
            list.add(future);
        }
        for(Future fut : list){
            try {
                //imprimir el valor de retorno de Future, ten en cuenta el retraso en la consola
                //porque Future.get() espera a que la tarea se complete
                System.out.println(new Date()+ "::"+fut.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //apagar el servicio del executor ahora
        executor.shutdown();
    }

}

Una vez que ejecutamos el programa anterior, notarás el retraso en la salida porque el método get() de Java Future espera a que la tarea invocable de Java se complete. También observa que solo hay 10 hilos ejecutando estas tareas. Aquí hay un fragmento de la salida del programa anterior.

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
...

Consejo: ¿Qué pasa si queremos anular algunos de los métodos de la interfaz Java Future, por ejemplo, anular el método get() para que haya un tiempo de espera predeterminado en lugar de esperar indefinidamente? En este caso, la clase Java FutureTask resulta útil, ya que es la implementación base de la interfaz Future. Consulta Ejemplo de Java FutureTask para obtener más información sobre esta clase.

Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example