2012-12-14 15 views
52

Sto utilizzando un ExecutoreService in Java 1.6, iniziato semplicementeConvertire un ExecutorService al demone in Java

ExecutorService pool = Executors.newFixedThreadPool(THREADS). 

Quando il mio thread principale è finito (insieme a tutti i compiti elaborati dal pool di thread), questa piscina impedirà il mio programma di arrestare fino a quando ho chiamare esplicitamente

pool.shutdown(); 

Posso evitare di dover chiamare questo in qualche modo ruotando la filettatura interna Amministratore utilizzato da questa piscina in un filo demone? O mi sto perdendo qualcosa qui.

+1

io come autore di risposta attualmente accettato suggerirebbe la lettura approccio pubblicato da Marco13: http://stackoverflow.com/a/29453160/1393766 e cambiando segno di accettazione dal mio post per la sua, dal momento che la soluzione descritta non v'è probabilmente più semplice e si chiude a ciò che volevi ottenere originariamente. – Pshemo

+0

@Pshemo Lasciami non essere d'accordo con te ... Per favore controlla il mio commento sotto la risposta di Marco13. –

+0

@Pshemo In considerazione del suggerimento di Vladimirs, potresti considerare di sottolineare il fatto che la soluzione "semplice" potrebbe non essere sempre la preferita. – Marco13

risposta

71

Probabilmente la soluzione più semplice e preferita è in Marco13's answer quindi non farti ingannare dalla differenza di voto (la mia risposta ha qualche anno in più) o marchio di accettazione (significa solo che la soluzione mia era appropriata per le circostanze OP non è meglio) .


È possibile utilizzare ThreadFactory per impostare le discussioni all'interno esecutore di demoni. Ciò influirà sul servizio executor in modo che diventi anche un thread daemon in modo che esso (e i thread gestiti da esso) si fermeranno se non ci sarà nessun altro thread non daemon. Ecco semplice esempio:

ExecutorService exec = Executors.newFixedThreadPool(4, 
     new ThreadFactory() { 
      public Thread newThread(Runnable r) { 
       Thread t = Executors.defaultThreadFactory().newThread(r); 
       t.setDaemon(true); 
       return t; 
      } 
     }); 

exec.execute(YourTaskNowWillBeDaemon); 

Ma se si desidera ottenere esecutore che vi permetterà sua finitura compito, e al tempo stesso chiamerà automaticamente il suo metodo shutdown() quando l'applicazione è completa, si potrebbe voler avvolgere il tuo esecutore con Guava'sMoreExecutors.getExitingExecutorService.

ExecutorService exec = MoreExecutors.getExitingExecutorService(
     (ThreadPoolExecutor) Executors.newFixedThreadPool(4), 
     100_000, TimeUnit.DAYS//period after which executor will be automatically closed 
          //I assume that 100_000 days is enough to simulate infinity 
); 
//exec.execute(YourTask); 
exec.execute(() -> { 
    for (int i = 0; i < 3; i++) { 
     System.out.println("daemon"); 
     try { 
      TimeUnit.SECONDS.sleep(1); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
}); 
+1

Anche se questa risposta è stata accettata, non penso che questo sia ciò che l'OP intendeva: Penso che il programma dovrebbe spegnersi quando tutte le attività sono state elaborate. Quando si imposta il thread degli executors su 'daemon', il programma uscirà anche quando sono ancora in esecuzione i task. –

+0

@ArnoutEngelen Ho aggiornato la mia risposta per fornire un approccio alternativo che risolva anche questo problema, ma ritengo che [il post di Marco13] (http://stackoverflow.com/a/29453160/1393766) contenga l'approccio migliore. – Pshemo

4

Sì.

È sufficiente creare la propria classe ThreadFactory che crea thread daemon anziché normali thread.

26

C'è già una funzionalità built-in per la creazione di un ExecutorService che termina tutte le discussioni dopo un certo periodo di inattività: è possibile creare un ThreadPoolExecutor, passare le informazioni di temporizzazione desiderata, e quindi chiamare allowCoreThreadTimeout(true) su questo esecutore servizio:

/** 
* Creates an executor service with a fixed pool size, that will time 
* out after a certain period of inactivity. 
* 
* @param poolSize The core- and maximum pool size 
* @param keepAliveTime The keep alive time 
* @param timeUnit The time unit 
* @return The executor service 
*/ 
public static ExecutorService createFixedTimeoutExecutorService(
    int poolSize, long keepAliveTime, TimeUnit timeUnit) 
{ 
    ThreadPoolExecutor e = 
     new ThreadPoolExecutor(poolSize, poolSize, 
      keepAliveTime, timeUnit, new LinkedBlockingQueue<Runnable>()); 
    e.allowCoreThreadTimeOut(true); 
    return e; 
} 

EDIT Riferendosi alle osservazioni nei commenti: si noti che questo pool di thread esecutore non si spegne automaticamente alla chiusura dell'applicazione. L'esecutore continuerà a funzionare dopo l'uscita dall'applicazione, ma non oltre il keepAliveTime. Se, a seconda dei precisi requisiti dell'applicazione, il keepAliveTime deve essere più lungo di alcuni secondi, la soluzione nel answer by Pshemo potrebbe essere più appropriata: quando i thread sono impostati come thread daemon, terminano immediatamente quando l'applicazione si chiude.

+0

Questa è un'informazione molto interessante. +1. Quindi, se ho capito bene, possiamo semplicemente rendere più veloci le risorse dei thread di Executor, inclusi anche quelli core. Ma solo la mancanza di risorse non significa che l'esecutore verrà arrestato quando l'ultima risorsa verrà rimossa. Lo spegnimento verrà chiamato automaticamente quando Executor non avrà risorse (e nuove attività da eseguire) e l'applicazione sarà completa. – Pshemo

+1

@Pshemo Sì, questo non è un "arresto" nel senso come nel metodo 'shutdown'. L'ho riformulato un po ', spero che ora sia meno ambiguo. – Marco13

+0

@Pshemo Grazie per la vostra generosità. Questa è una grande attenzione per il suggerimento di chiamare un singolo metodo ;-) – Marco13

10

Vorrei utilizzare la classe ThreadFactoryBuilder di Guava.

ExecutorService threadPool = Executors.newFixedThreadPool(THREADS, new ThreadFactoryBuilder().setDaemon(true).build()); 

Se non stai già utilizzando Guava, mi piacerebbe andare con una sottoclasse ThreadFactory come descritto nella parte superiore del Pshemo's answer

+1

Puoi spiegare qual è la differenza tra l'approccio dalla tua risposta e la risposta accettata? Da quello che ho controllato nel codice sorgente di ThreadFactoryBuilder creerà ThreadFactory con lo stesso identico comportamento presentato nella mia risposta. Ho perso qualcosa o il punto della tua risposta è stato quello di mostrare che con Guava possiamo abbreviare questo codice un po '? A proposito, non sto dicendo che la tua risposta è sbagliata, sto solo cercando di capirlo meglio. – Pshemo

+3

È più conciso. Se stai già usando Guava, perché riscrivere il codice che esiste nella libreria? Hai ragione che fa esattamente la stessa cosa. –

-1

Se si dispone di un elenco noto di compiti, non è necessario daemon fili a tutti. Puoi semplicemente chiamare shutdown() su ExecutorService dopo aver inviato tutte le tue attività.

Quando il thread principale è completo, utilizzare il metodo awaitTermination() per consentire il tempo per il completamento delle attività inoltrate. Le attività attualmente inviate verranno eseguite e il pool di thread interromperà il thread di controllo una volta completati.

for (Runnable task : tasks) { 
    threadPool.submit(task); 
} 
threadPool.shutdown(); 
/*... do other stuff ...*/ 
//All done, ready to exit 
while (!threadPool.isTerminated()) { 
    //this can throw InterruptedException, you'll need to decide how to deal with that. 
    threadPool.awaitTermination(1,TimeUnit.SECOND); 
} 
+1

Questa strategia non interromperà/fermerà le attività che seguono un modello 'eseguito fino all'interruzione', in cui i thread continueranno a essere eseguiti (poiché non sono daemon e non sono interrotti). È molto più sicuro impostare i thread su daemon se è importante fermarli effettivamente. – Krease

Problemi correlati