Sobes.tech
Middle

Come funzionano gli Executor in Java?

sobes.tech AI

Risposta dell'AI

Executor — è un'interfaccia in Java che definisce un contratto per eseguire compiti in un pool di thread. Invece di creare esplicitamente thread per ogni compito, si inviano i compiti agli esecutori, che gestiscono la creazione, l'uso e la distruzione dei thread.

Vantaggi principali:

  • Gestione dei thread: Fornisce un metodo unificato per gestire il pool di thread, evitando la creazione e la sincronizzazione manuale dei thread.
  • Efficienza: Riutilizza i thread esistenti, riducendo i costi di creazione e distruzione dei thread.
  • Prestazioni: Migliora le prestazioni e la reattività delle applicazioni grazie all'esecuzione asincrona dei compiti.

Executor ha un metodo:

// Esegue il comando dato in qualche momento nel futuro.
void execute(Runnable command);

Sottotipi comunemente usati:

  • ExecutorService: Estende Executor e fornisce metodi aggiuntivi per gestire il ciclo di vita dell'esecutore e ottenere i risultati dei compiti (ad esempio, tramite Future).
  • ScheduledExecutorService: Estende ExecutorService e permette di eseguire compiti con ritardo o secondo un programma.

La classe Executors fornisce metodi di fabbrica per creare diversi tipi di esecutori:

// Crea un pool di thread con un numero fisso di thread.
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

// Crea un pool di thread che può regolare dinamicamente il numero di thread.
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

// Crea un pool di thread che può eseguire compiti programmati.
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

Esempio di utilizzo:

// Oggetto esecutore
ExecutorService executor = Executors.newFixedThreadPool(2);

// Compito da eseguire
Runnable task = new Runnable() {
    @Override
    public void run() {
        // Codice del compito
        System.out.println("Compito in esecuzione nel thread: " + Thread.currentThread().getName());
    }
};

// Inviare il compito all'esecutore
executor.execute(task);

// Terminare l'esecutore (necessario per liberare risorse)
executor.shutdown();

Chiamando execute(), l'esecutore prende il compito (Runnable) e lo assegna a uno dei suoi thread per l'esecuzione. La gestione della distribuzione dei compiti tra i thread e il ciclo di vita è gestita dall'esecutore.