CompletableFuture.supplyAsync în Java

Pornește o sarcină pe alt fir și returnează imediat un CompletableFuture; supplyAsync are rezultat, runAsync nu.

Sintaxă
static <U> CompletableFuture<U> supplyAsync(Supplier<U> furnizor)
static <U> CompletableFuture<U> supplyAsync(Supplier<U> furnizor, Executor executor)
static CompletableFuture<Void> runAsync(Runnable sarcina)
static CompletableFuture<Void> runAsync(Runnable sarcina, Executor executor)

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 IOException din lambda lui supplyAsync. Nu compilează; învelește-o în UncheckedIOException sau RuntimeException.

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.