Atualizado: 02/11/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Tarefas Assíncronas com FutureTask, Callable e Future em Java

O método run() da interface Runnable, executado por uma thread, não retorna nenhum valor — apenas realiza uma ação. Entretanto, em muitos casos, o código executado em uma thread precisa produzir um resultado que possa ser recuperado depois. Para isso, o Java oferece os interfaces Callable e Future, definidos no pacote java.util.concurrent.

O Callable representa uma tarefa que retorna um resultado. Esse interface tem um parâmetro de tipo e um único método, call(), que devolve um valor desse tipo:

public interface Callable<V> {
    V call() throws Exception;
}

Em outras palavras, o método call() é executado em uma thread e retorna um resultado que pode ser obtido posteriormente.

A interface Future representa o resultado de uma tarefa assíncrona. Ele permite recuperar o valor produzido por um Callable assim que estiver disponível, além de oferecer meios para verificar o estado da execução e controlar sua finalização.

Alguns dos principais métodos de Future incluem:

  • boolean cancel(boolean mayInterruptIfRunning) – tenta cancelar a execução da tarefa.
  • V get() – bloqueia até a tarefa terminar e retorna o resultado.
  • V get(long timeout, TimeUnit unit) – aguarda o resultado por um tempo limitado.
  • boolean isCancelled() – indica se a tarefa foi cancelada.
  • boolean isDone() – indica se a tarefa terminou.
  • Throwable exceptionNow() – retorna a exceção gerada pela tarefa, se houver.
  • V resultNow() – retorna o resultado, se já estiver disponível, sem bloqueio.
  • Future.State state() – retorna o estado da tarefa, que pode ser CANCELLED, FAILED, RUNNING ou SUCCESS.

A Classe FutureTask

Uma das formas mais práticas de executar tarefas assíncronas é com a classe FutureTask, que implementa Future e Runnable. Ela representa uma tarefa que pode ser executada em uma thread e posteriormente cancelada, se necessário.

Por implementar Runnable, objetos de FutureTask podem ser passados diretamente a um construtor de Thread. Geralmente, FutureTask serve como uma "embalagem" para um Callable (ou, em alguns casos, um Runnable), permitindo executar a tarefa e obter o resultado no futuro.

Os principais construtores são:

FutureTask(Runnable runnable, V result)
FutureTask(Callable<V> callable)

O primeiro cria uma tarefa a partir de um Runnable, devolvendo o valor especificado quando a execução termina. O segundo cria uma tarefa baseada em um Callable, retornando o resultado do método call().

Entre os métodos mais importantes de FutureTask estão get() (para obter o resultado), cancel() (para cancelar a tarefa) e isDone() (para verificar se a execução terminou).


Exemplo de Execução com FutureTask

import java.util.concurrent.*;

class Program {

    public static void main(String[] args) {

        System.out.println("Main thread started...");

        int number = 5;  // número base para o cálculo do fatorial

        Callable<Integer> task = () -> {
            int n = number;
            int result = 1;
            while (n > 0) result *= n--;
            return result;
        };

        var futureTask = new FutureTask<Integer>(task);
        var t = new Thread(futureTask);
        t.start();

        System.out.println("Main thread works...");

        try {
            Integer factorial = futureTask.get();
            System.out.printf("Factorial of %d is %d\n", number, factorial);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        System.out.println("Main thread finished...");
    }
}

Saída esperada:

Main thread started...
Main thread works...
Factorial of 5 is 120
Main thread finished...

O código define uma tarefa Callable que calcula o fatorial de um número e a executa em uma thread separada por meio de um FutureTask. O método get() bloqueia a thread principal até que o resultado esteja disponível, retornando o valor final.


Tratamento de Exceções

O método call() pode lançar exceções, e quando isso ocorre dentro de um FutureTask, a exceção é encapsulada em um ExecutionException. Assim, é possível capturar e tratar erros que acontecem durante a execução da tarefa.

import java.util.concurrent.*;

class Program {

    public static void main(String[] args) {

        System.out.println("Main thread started...");

        int number = -5; // número inválido para fatorial

        try {
            Callable<Integer> task = () -> {
                if (number < 1) throw new Exception("Number must be greater than 0");
                int n = number;
                int result = 1;
                while (n > 0) result *= n--;
                return result;
            };

            var futureTask = new FutureTask<Integer>(task);
            var t = new Thread(futureTask);
            t.start();

            System.out.println("Main thread works...");

            Integer factorial = futureTask.get();
            System.out.printf("Factorial of %d is %d\n", number, factorial);
        }
        catch (ExecutionException ex) {
            System.out.println("Factorial error: " + ex.getMessage());
        }
        catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        System.out.println("Main thread finished...");
    }
}

Saída:

Main thread started...
Main thread works...
Factorial error: java.lang.Exception: Number must be greater than 0
Main thread finished...

Cancelamento de Tarefas

A interface Future também permite cancelar tarefas em execução por meio do método cancel().

boolean cancel(boolean mayInterruptIfRunning)

O parâmetro mayInterruptIfRunning indica se a thread que executa a tarefa pode ser interrompida. O método retorna true se o cancelamento for possível.

Exemplo:

import java.util.concurrent.*;

class Program {

    public static void main(String[] args) {

        System.out.println("Main thread started...");

        int number = 5;

        try {
            Callable<Integer> task = () -> {
                if (number < 1) throw new Exception("Number must be greater than 0");
                int n = number;
                int result = 1;
                while (n > 0) {
                    result *= n--;
                    System.out.printf("[Factorial execution] result = %d   n = %d\n", result, n);
                    Thread.sleep(200);
                }
                return result;
            };

            var futureTask = new FutureTask<Integer>(task);
            var t = new Thread(futureTask);
            t.start();

            System.out.println("Main thread works...");
            Thread.sleep(300);

            futureTask.cancel(true);

            if (futureTask.isCancelled())
                System.out.println("Factorial execution cancelled...");
        }
        catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        System.out.println("Main thread finished...");
    }
}

Saída esperada:

Main thread started...
Main thread works...
[Factorial execution] result = 5   n = 4
[Factorial execution] result = 20   n = 3
Factorial execution cancelled...
Main thread finished...

Neste exemplo, a tarefa é interrompida após algumas iterações, demonstrando o cancelamento de uma execução assíncrona.


Resumo

  • Callable define uma tarefa que retorna um resultado.
  • Future representa o resultado de uma tarefa assíncrona e permite controlá-la.
  • FutureTask combina ambos, podendo ser executado em uma thread e cancelado.
  • O método get() bloqueia até a conclusão e retorna o resultado.
  • O método cancel() tenta interromper a execução de uma tarefa.
  • Exceções dentro de tarefas são encapsuladas em ExecutionException.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com