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șteget(timp, unitate). - Afișezi direct
ExecutionException. Mesajul util este îne.getCause(). - Faci o buclă
while (!f.isDone()) {}. Consumă procesorul degeaba; apelează directget().
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.