2012-05-17 14 views
5

Per favore aiutatemi a trovare il motivo per Perdita di filo nel codice qui sotto. Lo TestThread non ottiene i dati inutili raccolti anche dopo che run() è stato completato (verificato dall'istruzione di stampa consolata) e il metodo principale è stato chiuso (verificato dall'istruzione print e dallo strumento profiler).Perché UserThread in esecuzione con ScheduleExecutorService non recupera dati inutili

Il numero TestThread, tuttavia, viene raccolto automaticamente se è impostato come thread daemon, ad esempio t.setDaemon(true). Il codice seguente è solo un esempio di codice che illustra il problema nella mia applicazione. Sto cercando di utilizzare alcune classi di pianificazione preesistenti (progettate da qualcun altro che utilizza ScheduledExecutorService). Ho notato che quando continuo a programmare più Runnable s con la classe, i thread creati non ottengono mai la garbage collection.

public class ThreadTest { 

    static void runThreadWithExecutor() { 
    final String name = "TestThread"; 
    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(
     new ThreadFactory() { 
      @Override 
      public Thread newThread(Runnable r) { 
      Thread t = new Thread(r, name); 
      t.setDaemon(false); 
      return t; 
      } 
     }); 

    ses.schedule(new Runnable() { 
     @Override 
     public void run() { 
      System.out.println("entered " + name); 
      System.out.println("exiting " + name); 
     }}, 
     2, 
     TimeUnit.SECONDS); 
    } 

    public static void main(String[] args) throws InterruptedException { 
    System.out.println("entered main"); 
    runThreadWithExecutor(); 
    Thread.sleep(5000); 
    System.out.println("exiting main"); 
    } 
} 

risposta

5

Ciò è dovuto al fatto che non si sta chiamando shutdown() sul vostro servizio esecutore dopo aver pianificato il tuo ultimo lavoro:

ses.schedule(...); 
// this stops any management threads but existing jobs will still run 
ses.shutdown(); 

Ho appena aggiunto la chiamata shutdown() al codice ed esce bene. Questo è vero per tutti gli ExecutorService s. Senza lo shutdown, il pool di thread continua ad attendere la presentazione di altri lavori e non viene mai eseguito da GC.

Vedere la risposta di John qui sotto per ulteriori dettagli.

3

@Gray è corretto con la sua valutazione, ho appena capito che aggiungo il motivo per cui è corretto. ExecutorService è un pool di thread che riutilizzerà i thread.

A differenza di new Thread(runnable).start(); quando il metodo di esecuzione termina, il thread viene completato e sarà quindi convertito in GC. Una volta completato un Executor Runnable, il thread si posizionerà lì e attenderà che venga eseguita e utilizzata un'altra attività eseguibile. Quindi, chiudendo, stai dicendo all'Esecutore di chiudere tutti i Thread nel pool di thread.

Per rispondere alla tua ultima parte. L'impostazione su daemon funziona solo perché non ci sono altri thread (non daemon) in esecuzione. Se l'applicazione ha avviato un altro thread non daemon, il thread di Executor continuerà. Ricorda che un thread daemon verrà ucciso quando sono in esecuzione solo i thread daemon.

+2

Buone informazioni John. Un pizzico. 'shutdown()' non chiude tutti i thread nel pool di thread fino a quando tutti i lavori non hanno già terminato l'esecuzione. – Gray

+0

@Gray Buon punto –

+0

Grazie ragazzi. Anche se inizialmente ho scelto questa come risposta accettata, in seguito ho scelto Chose Gray perché questa risposta non è auto-esplicativa senza quella di Gray. Questa risposta, tuttavia, mi ha dato la spiegazione completa necessaria per modificare il codice con fiducia :) e funziona! – Kes115

Problemi correlati