lezione 07

concorrenza ed executor

thread pool, future e sincronizzazione per servizi scalabili.

livello: avanzato durata: 45 min output: task paralleli badge: executors

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

  • synchronized per sezioni critiche brevi.
  • ReentrantLock quando 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.

start a brief