quando usare thread
la concorrenza serve quando il lavoro è CPU-bound o I/O-bound e può essere eseguito in parallelo. evita la complessità se il guadagno è minimo.
focus: thread pool stabili + task piccoli e indipendenti.
executor service
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> doWork());
pool.shutdown();
chiudi sempre l'executor con shutdown o shutdownNow in caso di fallback.
future e completablefuture
CompletableFuture<String> future =
CompletableFuture.supplyAsync(() -> fetchData())
.thenApply(data -> transform(data));
String result = future.join();
usa pipeline async per comporre task senza bloccare thread principali.
sincronizzazione
synchronizedper sezioni critiche brevi.ReentrantLockquando servono timeout e controlli extra.- collezioni thread-safe:
ConcurrentHashMap,CopyOnWriteArrayList.
private final Object lock = new Object();
synchronized (lock) {
sharedState++;
}
pitfalls
- deadlock dovuti a lock presi in ordine diverso.
- thread leak se non chiudi l'executor.
- shared state non protetto che genera race condition.
tip: logga sempre i tempi di coda e saturazione del pool.
checklist finale
- dimensiona il pool in base a CPU o I/O.
- usa future/async per composizione fluida.
- proteggi lo stato condiviso con lock o strutture concorrenti.
- monitora tempi di risposta e backlog.
panoramica
In questo capitolo su concorrenza ed executor, thread pool, future e sincronizzazione per servizi scalabili. L'obiettivo è trasformare i concetti in micro-pattern riutilizzabili con esempi piccoli e verificabili.
Lavora in sequenza: leggi, prova, modifica gli snippet e annota i trade-off principali (performance, leggibilità, manutenzione).
badge: executors
obiettivi
- capire e applicare quando usare thread in uno scenario reale
- capire e applicare executor service in uno scenario reale
- capire e applicare future e completablefuture in uno scenario reale
- capire e applicare sincronizzazione in uno scenario reale
scheda rapida
import java.util.List;
public class Main {
public static void main(String[] args) {
var dati = List.of(1, 2, 3);
var out = dati.stream().map(x -> x * 2).toList();
System.out.println(out);
}
}
Adatta questo scheletro agli esempi della lezione e sostituisci i dati con il tuo dominio.
tips
- organizza package per dominio
- preferisci immutabilità dove possibile
- documenta le API pubbliche
- chiudi ExecutorService
- usa Future per risultati
- limita thread pool
tip: Un thread leak è un memory leak con tempi peggiori.
mini progetto
Batch di task di rendering.
- crea pool fisso
- submit dei task
- raccogli risultati
- shutdown corretto
output atteso: uno script o query ripetibile con risultati verificabili.