Ce face CompletableFuture.supplyAsync
supplyAsync rulează un Supplier (o lambda fără parametri care returnează o valoare) pe alt fir și returnează un CompletableFuture cu acea valoare. runAsync face la fel pentru o sarcină fără rezultat; tipul este CompletableFuture<Void>, iar join() returnează null.
Fără al doilea argument, sarcinile rulează în ForkJoinPool.commonPool(), un grup de fire comun întregului program. Pentru sarcini care așteaptă mult (rețea, fișiere) dă un executor propriu, de exemplu unul cu fire virtuale.
Lambda din supplyAsync nu poate arunca excepții verificate (Supplier nu le permite). Le prinzi în lambda și le arunci din nou ca excepții neverificate.
Parametri
| Parametru | Descriere |
|---|---|
furnizor |
Lambda care calculează rezultatul: () -> valoare. |
sarcina |
Lambda fără rezultat, pentru runAsync. |
executor |
Opțional: executorul pe care rulează sarcina. |
Ce returnează
Un CompletableFuture<U> (sau <Void> pentru runAsync) care se completează când sarcina se termină.
Exemple
Exemplul 1: Două calcule pornite în paralel
Ambele sarcini pornesc imediat și durează câte 300 ms. Rulează în același timp, deci așteptarea totală este de aproximativ 300 ms, nu 600 ms.
import java.util.concurrent.CompletableFuture;
public class Main {
static int pauza(int ms, int valoare) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return valoare;
}
public static void main(String[] args) {
CompletableFuture<Integer> stocIasi = CompletableFuture.supplyAsync(() -> pauza(300, 120));
CompletableFuture<Integer> stocCluj = CompletableFuture.supplyAsync(() -> pauza(300, 85));
int total = stocIasi.join() + stocCluj.join();
System.out.println("Stoc Iași: " + stocIasi.join() + ", stoc Cluj: " + stocCluj.join());
System.out.println("Stoc total: " + total + " bucăți");
}
}
Rezultat
Stoc Iași: 120, stoc Cluj: 85
Stoc total: 205 bucăți
Exemplul 2: runAsync pe un executor propriu
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletableFuture<Void> trimitere = CompletableFuture.runAsync(
() -> System.out.println("Trimit SMS către 0722 000 000: Programarea de mâine, ora 10:00"),
executor);
Object rezultat = trimitere.join();
System.out.println("Rezultatul lui runAsync: " + rezultat);
}
}
}
Rezultat
Trimit SMS către 0722 000 000: Programarea de mâine, ora 10:00
Rezultatul lui runAsync: null
Greșeli frecvente
- Faci operații lente de rețea pe
commonPool(). Are puține fire (procesoare − 1) și poate bloca alte părți ale programului; dă un executor propriu. - Încerci să arunci o
IOExceptiondin lambda luisupplyAsync. Nu compilează; învelește-o înUncheckedIOExceptionsauRuntimeException.
Comenzi înrudite
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.CompletableFuture.thenApply: thenApply transformă rezultatul când este gata (ca map); thenAccept îl folosește fără să returneze ceva (ca forEach).CompletableFuture.allOf: Returnează un CompletableFuture care se termină când s-au terminat toate cele primite; anyOf, când s-a terminat primul.ExecutorService.submit: Trimite o sarcină executorului și returnează imediat un Future din care iei mai târziu rezultatul.