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;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CallableFutureExample {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // Definimos una tarea que calcula un valor y devuelve un resultado
        Callable<Long> tareaPesada = () -> {
            System.out.println("[" + Thread.currentThread().getName() + "] Iniciando cálculo intensivo...");
            long suma = 0;
            for (long i = 1; i <= 20_000_000L; i++) {
                suma += i;
            }
            Thread.sleep(200); // Simula latencia adicional
            System.out.println("[" + Thread.currentThread().getName() + "] Cálculo finalizado.");
            return suma;
        };

        // pool.submit() devuelve un Future que representa el resultado futuro
        Future<Long> futuro = pool.submit(tareaPesada);

        System.out.println("[main] Tarea enviada al pool. El hilo principal continúa haciendo otro trabajo...");

        try {
            // Ejemplo de consulta no bloqueante
            if (!futuro.isDone()) {
                System.out.println("[main] La tarea sigue ejecutándose en segundo plano...");
            }

            // future.get() BLOQUEA al hilo main hasta que la tarea en el pool concluya
            Long resultado = futuro.get(2, TimeUnit.SECONDS);
            System.out.println("[main] Resultado obtenido con éxito: " + resultado);

        } catch (TimeoutException e) {
            System.err.println("[main] La tarea excedió el tiempo límite permitido.");
            futuro.cancel(true); // Cancela la tarea interrumpiendo el hilo trabajador
        } catch (InterruptedException e) {
            System.err.println("[main] Hilo principal interrumpido mientras esperaba.");
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            System.err.println("[main] La tarea lanzó una excepción durante su ejecución: " + e.getCause());
        } finally {
            // Cierre ordenado del pool
            pool.shutdown();
        }
    }
}
