Future în Java

Rezultatul unei sarcini care rulează pe alt fir: get() așteaptă și îl returnează, isDone() spune dacă s-a terminat.

Sintaxă
import java.util.concurrent.Future;

V get() throws InterruptedException, ExecutionException
V get(long timp, TimeUnit unitate) throws InterruptedException, ExecutionException, TimeoutException
boolean isDone()
V resultNow()

Ce face Future

Un Future<V> este o promisiune pentru o valoare de tipul V care va fi gata mai târziu. Îl primești de la ExecutorService.submit sau invokeAll.

get() blochează firul curent până când sarcina se termină, apoi returnează rezultatul. Dacă sarcina a aruncat o excepție, get() aruncă ExecutionException, iar excepția originală se află în getCause(). Varianta get(timp, unitate) renunță după timpul dat cu TimeoutException (sarcina continuă să ruleze).

isDone() nu blochează: returnează true dacă sarcina s-a terminat (cu succes, cu eroare sau anulată). Din Java 19, resultNow() returnează rezultatul fără excepții verificate, dar doar pentru o sarcină deja terminată cu succes.

Parametri

Parametru Descriere
timp Cât să aștepte cel mult get.
unitate Unitatea pentru timp.

Ce returnează

get() returnează rezultatul sarcinii; isDone() returnează un boolean.

Exemple

Exemplul 1: isDone înainte și după get

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            Future<String> raport = executor.submit(() -> {
                Thread.sleep(500);
                return "Raport lunar: 42 de comenzi";
            });
            System.out.println("Gata imediat? " + raport.isDone());
            System.out.println(raport.get());
            System.out.println("Gata după get? " + raport.isDone());
            System.out.println("resultNow: " + raport.resultNow());
        }
    }
}

Rezultat

Gata imediat? false
Raport lunar: 42 de comenzi
Gata după get? true
resultNow: Raport lunar: 42 de comenzi

Exemplul 2: get cu limită de timp

Sarcina are nevoie de 2 secunde, dar așteptăm doar 200 ms. Primim TimeoutException, apoi anulăm sarcina.

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 Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            Future<Double> curs = executor.submit(() -> {
                Thread.sleep(2000);
                return 4.97;
            });
            try {
                System.out.println("Curs EUR: " + curs.get(200, TimeUnit.MILLISECONDS));
            } catch (TimeoutException e) {
                System.out.println("Serviciul de curs nu a răspuns la timp; folosesc ultimul curs salvat: 4.97");
                curs.cancel(true);
            }
        }
    }
}

Rezultat

Serviciul de curs nu a răspuns la timp; folosesc ultimul curs salvat: 4.97

Exemplul 3: ExecutionException și cauza ei

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            int numarNote = 0;
            Future<Integer> medie = executor.submit(() -> 28 / numarNote);
            try {
                medie.get();
            } catch (ExecutionException e) {
                System.out.println("Tip: " + e.getCause().getClass().getSimpleName());
                System.out.println("Mesaj: " + e.getCause().getMessage());
            }
        }
    }
}

Rezultat

Tip: ArithmeticException
Mesaj: / by zero

Greșeli frecvente

  • Apelezi get() fără limită pe o sarcină care poate rămâne blocată (de exemplu o cerere de rețea). Programul așteaptă la nesfârșit; folosește get(timp, unitate).
  • Afișezi direct ExecutionException. Mesajul util este în e.getCause().
  • Faci o buclă while (!f.isDone()) {}. Consumă procesorul degeaba; apelează direct get().

Comenzi înrudite

  • ExecutorService.submit: Trimite o sarcină executorului și returnează imediat un Future din care iei mai târziu rezultatul.
  • Future.cancel: Anulează o sarcină: dacă nu a pornit, nu mai rulează; dacă rulează, o poate întrerupe.
  • CompletableFuture: Un Future care se poate înlănțui: definești ce se întâmplă cu rezultatul (thenApply, thenAccept) fără să aștepți; join() îl ia la final.
  • ExecutorService.invokeAll: Trimite o listă de sarcini și așteaptă să se termine toate; returnează lista de Future în aceeași ordine.