Perché utilizzare ExecutorService per thread a esecuzione prolungata?

7

Voglio un oggetto che genera un thread daemon che continuerà a essere eseguito per tutta la durata del processo. Diciamo, solo per il gusto dell'argomento, che si tratta di un thread in un sistema embedded e attende di ricevere e gestire i comandi su alcune porte diagnostiche. Ma potrebbe essere qualsiasi cosa veramente. L'idea principale è che è che guarda qualcosa per un lungo periodo di tempo; Non sta eseguendo una sequenza di attività .

La saggezza comune di Java dice: Mai istanziare Thread , usa invece ExecutorService . (Ad es., Vedi questa risposta ) Ma qual è il vantaggio? Usare un thread pool come mezzo per creare un singolo thread di lunga durata sembra inutile. Come sarebbe meglio se scrivessi questo?

class Foobar {
    public Foobar() {
        this.threadFactory = Executors.defaultThreadFactory();
        ...
    }

    public Foobar(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        ...
    }

    public void start() {
        fooThread = threadFactory.newThread(new Runnable() { ... });
        fooThread.setDaemon(true);
        fooThread.start();
    }
    ...
}

Nota: questa domanda sembra simile alla mia, ma le risposte dicono solo come utilizzare un pool di thread, non perché .

    
posta Solomon Slow 10.05.2017 - 21:20
fonte

1 risposta

10

Penso che "Mai" sia una parola troppo strong. È più simile alla seconda regola di ottimizzazione: "Non (ancora)".

Secondo me, la ragione principale per utilizzare un servizio executor è gestire il numero di thread in esecuzione. Se si consente alle classi arbitrarie di creare i propri thread, è possibile trovarsi rapidamente con 1000 thread legati alla CPU (o in continua commutazione di contesto). Un servizio executor risolve questo problema, fornendo vincoli sulla creazione del thread.

Un motivo secondario è che correttamente iniziare un thread richiede qualche riflessione:

  • Daemon o non daemon? Ottieni questo errore e devi chiamare System.exit() per chiudere il programma.
  • Quale priorità? Molti programmatori Swing pensavano di essere intelligenti girando i thread in background per gestire le attività a uso intensivo della CPU, ma non si rendevano conto che il thread di invio eventi viene eseguito con la massima priorità e i thread figlio ereditano la priorità dei loro genitori.
  • Come gestire le eccezioni non rilevate?
  • Che nome appropriato? Sembra stupido ossessionare un nome, ma i thread con lo scopo ti danno un grande aiuto nel debug.

Detto questo, ci sono certamente casi in cui è opportuno far girare i thread piuttosto che fare affidamento su un pool di thread.

  • Vorrei utilizzare il pool di thread nel caso in cui la mia applicazione sta generando attività e voglio controllare come vengono eseguite tali attività.
  • Creerei thread dedicati in cui uno o alcuni thread sono dedicati all'elaborazione di eventi generati esternamente .

"Generato esternamente" dipende dal contesto. Il caso classico è il thread alla fine di una coda o socket di messaggi, che ha bisogno di eseguire il polling di quella coda ed eseguire alcune azioni (che possono comportare l'invio di un'attività a un pool).

Tuttavia, potrebbe anche riferirsi a eventi generati al di fuori di un particolare modulo: ad esempio, ritengo perfettamente ragionevole che AsyncAppender di Log4J giri la propria thread invece di aspettarsi che l'applicazione fornisca un pool.

    
risposta data 10.05.2017 - 23:50
fonte

Leggi altre domande sui tag