Ce face ExecutorService.invokeAll
invokeAll primește o colecție de Callable, le trimite pe toate executorului și așteaptă până se termină toate. Lista de Future returnată are aceeași ordine ca lista de sarcini, deci get() pe fiecare element nu mai blochează.
Varianta cu timp, invokeAll(sarcini, timp, unitate), anulează sarcinile care nu s-au terminat în timpul dat. Metoda înrudită invokeAny returnează rezultatul primei sarcini care reușește și le anulează pe celelalte.
Parametri
| Parametru | Descriere |
|---|---|
sarcini |
O colecție (de obicei List) de Callable<T>. |
Ce returnează
List<Future<T>>, în ordinea sarcinilor; toate sunt terminate (isDone() este true).
Exemple
Exemplul 1: Prețul total al unor coșuri de cumpărături
import java.util.List;
import java.util.concurrent.Callable;
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 {
List<Callable<Integer>> sarcini = List.of(
() -> 12 + 7 + 30,
() -> 99 + 1,
() -> 45 * 2
);
try (ExecutorService executor = Executors.newFixedThreadPool(3)) {
List<Future<Integer>> rezultate = executor.invokeAll(sarcini);
int nr = 1;
for (Future<Integer> f : rezultate) {
System.out.println("Coșul " + nr++ + ": " + f.get() + " lei (gata: " + f.isDone() + ")");
}
}
}
}
Rezultat
Coșul 1: 49 lei (gata: true)
Coșul 2: 100 lei (gata: true)
Coșul 3: 90 lei (gata: true)
Exemplul 2: invokeAll cu limită de timp
Sarcina lentă nu se termină în 500 ms, deci este anulată; isCancelled() arată asta.
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws Exception {
Callable<String> rapid = () -> "Iași: 14°C";
Callable<String> lent = () -> {
Thread.sleep(5000);
return "Cluj: 11°C";
};
try (ExecutorService executor = Executors.newFixedThreadPool(2)) {
List<Future<String>> rezultate = executor.invokeAll(List.of(rapid, lent), 500, TimeUnit.MILLISECONDS);
for (Future<String> f : rezultate) {
System.out.println(f.isCancelled() ? "anulată (prea lentă)" : f.get());
}
}
}
}
Rezultat
Iași: 14°C
anulată (prea lentă)
Exemplul 3: invokeAny: primul răspuns câștigă
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
static Callable<String> server(String nume, int ms) {
return () -> {
Thread.sleep(ms);
return "răspuns de la " + nume;
};
}
public static void main(String[] args) throws Exception {
try (ExecutorService executor = Executors.newFixedThreadPool(3)) {
String r = executor.invokeAny(List.of(server("București", 600), server("Frankfurt", 100), server("Londra", 900)));
System.out.println(r);
}
}
}
Rezultat
răspuns de la Frankfurt
Greșeli frecvente
- Dai lui
invokeAllo listă deRunnable. Primește doarCallable; o lambda fărăreturnnu se potrivește. - Uiți că
invokeAllblochează. Dacă vrei să faci altceva cât timp rulează sarcinile, foloseștesubmitpentru fiecare.
Comenzi înrudite
ExecutorService.submit: Trimite o sarcină executorului și returnează imediat un Future din care iei mai târziu rezultatul.Future: Rezultatul unei sarcini care rulează pe alt fir: get() așteaptă și îl returnează, isDone() spune dacă s-a terminat.CompletableFuture.allOf: Returnează un CompletableFuture care se termină când s-au terminat toate cele primite; anyOf, când s-a terminat primul.ExecutorService: Un grup de fire de execuție care primește sarcini și le rulează; se oprește cu shutdown() și se așteaptă cu awaitTermination().