Entendendo as Interfaces Callable e Future em Java

Java oferece duas formas de criar threads: usando a classe Thread ou a interface Runnable. Porém, Runnable não permite retornar resultados após a conclusão da thread. A interface Callable resolve esse problema, definindo um método call() que retorna um valor ao finalizar.

  • call() pode retornar resultados e lançar exceções, diferentemente de run()
  • Threads não podem ser criadas diretamente com Callable, apenas através de Runnable
import java.util.Random;
import java.util.concurrent.Callable;

class GeradorNumerico implements Callable<Integer> {
    public Integer call() throws Exception {
        Random rand = new Random();
        int numero = rand.nextInt(5);
        Thread.sleep(numero * 1000); // Simula processamento
        return numero;
    }
}

Interface Future

Future armazena resultados de operações assíncronas, permitindo que a thread principal acompanhe o prgoresso e recupere resultados. Principais métodos:

  • cancel(boolean): Interrompe a tarefa
  • get(): Recupera o resultado (bloqueante)
  • isDone(): Verifica conclusão

Exemplo 1: ExecutorService com Callable

import java.util.*;
import java.util.concurrent.*;

public class ExecutorCallable implements Callable<String> {
    private final int id;
    
    public ExecutorCallable(int id) {
        this.id = id;
    }
    
    public static void main(String[] args) throws Exception {
        final int TAREFAS = 5;
        ExecutorService executor = Executors.newFixedThreadPool(TAREFAS);
        List<Future<String>> resultados = new ArrayList<>();
        
        for (int i = 0; i < TAREFAS; i++) {
            resultados.add(executor.submit(new ExecutorCallable(i)));
        }
        
        executor.shutdown();
        
        for (Future<String> f : resultados) {
            System.out.println(f.get());
        }
    }
    
    @Override
    public String call() throws Exception {
        System.out.println("Tarefa " + id + " iniciada");
        long inicio = System.currentTimeMillis();
        Thread.sleep(1000);
        long duracao = System.currentTimeMillis() - inicio;
        return "Tarefa " + id + " concluída em " + duracao + "ms";
    }
}

Exemplo 2: FutureTask com Threads

import java.util.Random;
import java.util.concurrent.*;

public class FutureTaskDemo {
    public static void main(String[] args) throws Exception {
        FutureTask<Integer>[] tarefas = new FutureTask[5];
        
        for (int i = 0; i < tarefas.length; i++) {
            Callable<Integer> callable = new GeradorNumerico();
            tarefas[i] = new FutureTask<>(callable);
            new Thread(tarefas[i]).start();
        }
        
        for (FutureTask<Integer> ft : tarefas) {
            System.out.println("Resultado: " + ft.get());
        }
    }
}

Exemplo 3: Runnable com Retorno

import java.util.Random;
import java.util.concurrent.FutureTask;

class RunnableComRetorno implements Runnable {
    private Object resultado;
    
    public void run() {
        try {
            Random rand = new Random();
            int numero = rand.nextInt(5);
            Thread.sleep(numero * 1000);
            resultado = numero;
            synchronized(this) {
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public synchronized Object getResultado() throws InterruptedException {
        while (resultado == null) wait();
        return resultado;
    }
}

public class TesteRunnable {
    public static void main(String[] args) throws Exception {
        RunnableComRetorno[] tarefas = new RunnableComRetorno[5];
        
        for (int i = 0; i < tarefas.length; i++) {
            tarefas[i] = new RunnableComRetorno();
            new Thread(tarefas[i]).start();
        }
        
        for (RunnableComRetorno r : tarefas) {
            System.out.println(r.getResultado());
        }
    }
}

Tags: java Concorrência Callable future ExecutorService

Publicado em 7-18 08:24