Ce face ExecutorService.submit
submit pune sarcina în coada executorului și revine imediat, fără să aștepte. Primești un Future: o „chitanță” pentru rezultatul care va veni. Rezultatul îl iei cu future.get(), care așteaptă până când sarcina se termină.
Sarcina poate fi un Callable (o lambda care returnează o valoare și poate arunca excepții verificate) sau un Runnable (o lambda fără valoare). Dacă lambda are return cu o valoare, Java alege Callable.
Diferența față de execute: dacă sarcina aruncă o excepție, submit o păstrează în Future și o primești la get(), învelită într-o ExecutionException. Cu execute, excepția se afișează pe ecran și se pierde.
Parametri
| Parametru | Descriere |
|---|---|
sarcina |
Un Callable<T> (cu rezultat) sau un Runnable (fără rezultat). |
Ce returnează
Un Future<T>. Pentru un Runnable, get() returnează null.
Exemple
Exemplul 1: Calcule în paralel, rezultate în ordine
Sarcinile rulează în paralel, dar rezultatele sunt citite din lista de Future în ordinea trimiterii.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
static int sumaNote(int[] note) throws InterruptedException {
Thread.sleep(100);
int s = 0;
for (int n : note) s += n;
return s;
}
public static void main(String[] args) throws Exception {
String[] elevi = {"Ana", "Mihai", "Ioana"};
int[][] note = {{9, 10, 8}, {7, 6, 9}, {10, 10, 9}};
List<Future<Integer>> rezultate = new ArrayList<>();
try (ExecutorService executor = Executors.newFixedThreadPool(3)) {
for (int[] n : note) {
rezultate.add(executor.submit(() -> sumaNote(n)));
}
for (int i = 0; i < elevi.length; i++) {
System.out.println(elevi[i] + ": suma notelor = " + rezultate.get(i).get());
}
}
}
}
Rezultat
Ana: suma notelor = 27
Mihai: suma notelor = 22
Ioana: suma notelor = 29
Exemplul 2: Excepția sarcinii ajunge la get()
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()) {
Future<Integer> f = executor.submit(() -> Integer.parseInt("doi"));
try {
System.out.println(f.get());
} catch (ExecutionException e) {
System.out.println("Sarcina a eșuat: " + e.getCause());
}
}
}
}
Rezultat
Sarcina a eșuat: java.lang.NumberFormatException: For input string: "doi"
Exemplul 3: Runnable: Future fără valoare
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<?> f = executor.submit(() -> System.out.println("Trimit e-mailul către ana@exemplu.ro"));
System.out.println("Rezultat: " + f.get());
}
}
}
Rezultat
Trimit e-mailul către ana@exemplu.ro
Rezultat: null
Greșeli frecvente
- Apelezi
get()imediat după fiecaresubmit, în aceeași buclă. Aștepți fiecare sarcină înainte s-o trimiți pe următoarea, deci nu mai rulează nimic în paralel. Trimite întâi toate sarcinile, apoi citește rezultatele. - Trimiți cu
submitși nu apelezi niciodatăget(). Dacă sarcina aruncă o excepție, nu o vezi nicăieri.
Comenzi înrudite
Future: Rezultatul unei sarcini care rulează pe alt fir: get() așteaptă și îl returnează, isDone() spune dacă s-a terminat.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().ExecutorService.invokeAll: Trimite o listă de sarcini și așteaptă să se termine toate; returnează lista de Future în aceeași ordine.CompletableFuture.supplyAsync: Pornește o sarcină pe alt fir și returnează imediat un CompletableFuture; supplyAsync are rezultat, runAsync nu.