Inviare attività: Runnable e Callable a confronto
Invii attività Runnable e Callable e recuperi i risultati tramite Future.
Inviare attività: Runnable e Callable a confronto è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.
Runnable e Callable
Due interfacce funzionali rappresentano le attività sottomesse a ExecutorService:
- Runnable: non restituisce un valore e non può dichiarare eccezioni checked
- Callable<V>: restituisce un risultato di tipo V e può generare eccezioni checked
import java.util.concurrent.*;
// Runnable — no return value
Runnable r = () -> System.out.println("Running");
// Callable<Integer> — returns a value
Callable<Integer> c = () -> {
return 42; // or do computation
};submit(Runnable)
submit(Runnable) restituisce un Future<?>. Chiamare get() su di esso restituisce null, ma conferma che l'attività è stata completata, oppure genera un'eccezione se l'attività non è riuscita.
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<?> future = pool.submit(() ->
System.out.println("Task done on " + Thread.currentThread().getName())
);
future.get(); // waits for completion; returns null
System.out.println("Task confirmed complete");
pool.shutdown();submit(Callable<V>)
submit(Callable) restituisce un Future<V>. Chiami future.get() per recuperare il risultato: l'operazione si blocca fino al completamento.
ExecutorService pool = Executors.newFixedThreadPool(2);
Callable<Integer> sumTask = () -> {
int sum = 0;
for (int i = 1; i <= 100; i++) sum += i;
return sum;
};
Future<Integer> future = pool.submit(sumTask);
Integer result = future.get(); // blocks until done
System.out.println("Sum 1..100 = " + result); // 5050
pool.shutdown();Sottomissione di più Callable con invokeAll
invokeAll() sottomette una raccolta di Callable e restituisce una List di Future: tutti vengono completati prima del ritorno:
List<Callable<String>> tasks = List.of(
() -> "Result A",
() -> "Result B",
() -> "Result C"
);
ExecutorService pool = Executors.newFixedThreadPool(3);
List<Future<String>> futures = pool.invokeAll(tasks);
for (Future<String> f : futures) {
System.out.println(f.get());
}
pool.shutdown();invokeAny: primo risultato riuscito
invokeAny() sottomette una raccolta di Callable e restituisce il risultato del primo che viene completato con successo, annullando gli altri:
List<Callable<String>> candidates = List.of(
() -> { Thread.sleep(200); return "Slow"; },
() -> { Thread.sleep(50); return "Fast"; },
() -> { Thread.sleep(100); return "Medium"; }
);
ExecutorService pool = Executors.newFixedThreadPool(3);
String winner = pool.invokeAny(candidates);
System.out.println("First: " + winner); // Fast
pool.shutdown();execute() e submit()
execute(Runnable) esegue l'attività senza restituire risultati: non viene restituito alcun Future e le eccezioni vanno perse, a meno che non si aggiunga un gestore delle eccezioni non catturate. submit() racchiude l'attività in un Future, catturando le eccezioni per consentirne il recupero tramite get().
ExecutorService pool = Executors.newFixedThreadPool(2);
// execute: exception silently lost
pool.execute(() -> { throw new RuntimeException("Oops!"); });
// submit: exception captured in Future
Future<?> f = pool.submit(() -> { throw new RuntimeException("Oops!"); });
try {
f.get();
} catch (ExecutionException e) {
System.out.println("Caught: " + e.getCause().getMessage());
}
pool.shutdown();Callable con eccezioni checked
A differenza di Runnable, Callable può generare eccezioni checked, rendendolo adatto alle operazioni di I/O e sui database:
Callable<String> dbQuery = () -> {
// This compiles fine — checked exception is declared on Callable.call()
if (Math.random() < 0.5) throw new java.sql.SQLException("DB error");
return "row data";
};
Future<String> f = pool.submit(dbQuery);
try {
String data = f.get();
} catch (ExecutionException e) {
if (e.getCause() instanceof java.sql.SQLException) {
System.out.println("DB failed: " + e.getCause().getMessage());
}
}Parallelizzazione di calcoli indipendenti
Utilizzi più sottomissioni di Callable per eseguire calcoli indipendenti in parallelo:
ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Long> sumFuture = pool.submit(() -> LongStream.rangeClosed(1,1_000_000).sum());
Future<Long> prodFuture = pool.submit(() -> LongStream.rangeClosed(1,20).reduce(1L, (a,b)->a*b));
long sum = sumFuture.get();
long prod = prodFuture.get();
System.out.println("Sum: " + sum + ", 20!: " + prod);
pool.shutdown();Aggregazione dei risultati di Callable
Sottometta molte attività e aggreghi i risultati quando sono state completate tutte:
int N = 8;
ExecutorService pool = Executors.newFixedThreadPool(N);
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < N; i++) {
final int chunk = i;
futures.add(pool.submit(() -> chunk * chunk)); // i^2
}
int total = 0;
for (Future<Integer> f : futures) total += f.get();
System.out.println("Sum of squares: " + total);
pool.shutdown();Timeout per Callable
Passi un timeout a future.get(timeout, unit) per evitare di attendere indefinitamente:
Future<String> f = pool.submit(() -> {
Thread.sleep(5000); // slow task
return "done";
});
try {
String result = f.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Task timed out");
f.cancel(true); // interrupt the task
} catch (ExecutionException e) {
System.out.println("Task failed: " + e.getCause());
}Buone pratiche
Riepilogo delle buone pratiche:
- Preferisca
submit()aexecute(): le eccezioni vengono catturate - Utilizzi Callable quando è necessario un valore restituito o quando possono verificarsi eccezioni checked
- Chiami sempre
future.get()con un timeout - Utilizzi invokeAll per l'elaborazione in batch e invokeAny quando deve prevalere la prima risposta
- Arresti sempre il pool
Controllo rapido
Qual è il principale vantaggio di Callable rispetto a Runnable?
Riepilogo: Runnable e Callable
Punti chiave:
- Runnable: void, nessuna eccezione checked; submit restituisce Future<?> con valore null
- Callable: restituisce V e può generare eccezioni checked; submit restituisce Future<V>
- invokeAll: sottomette un batch e attende che tutte le attività terminino
- invokeAny: restituisce il primo risultato riuscito e annulla gli altri
- Utilizzi sempre submit() per catturare le eccezioni
Domande Frequenti
La lezione «Inviare attività: Runnable e Callable a confronto» è gratuita?
Sì — il testo completo di «Inviare attività: Runnable e Callable a confronto» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.
Cosa imparerò in «Inviare attività: Runnable e Callable a confronto»?
Invii attività Runnable e Callable e recuperi i risultati tramite Future. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Java Academy?
Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Inviare attività: Runnable e Callable a confronto»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Java Academy?
Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- ExecutorService e tipi di thread pool
- Inviare attività: Runnable e Callable a confronto
- Future e gestione degli errori
- ScheduledExecutorService per attività ricorrenti