2012-05-17 5 views
5

Bitte helfen Sie mir, den Grund für Thread-Leck in dem folgenden Code zu finden. Die TestThread ruft keine Garbage Collected ab, nachdem run() abgeschlossen wurde (bestätigt durch die consoled print-Anweisung) und die Hauptmethode beendet wurde (verifiziert von print statement und profiler tool).Warum UserThread, das mit ScheduleExecutorService ausgeführt wird, keinen Müll sammelt

Die TestThread wird jedoch Müll gesammelt, wenn es als Daemon Thread festgelegt ist, d. H. t.setDaemon(true). Der folgende Code ist nur ein Beispielcode, der das Problem in meiner Anwendung veranschaulicht. Ich versuche, eine bereits vorhandene Planungsklasse zu verwenden (die von jemand anderem mit ScheduledExecutorService entworfen wurde). Ich merke, dass, wenn ich mehrere Runnable s mit der Klasse einplane, die erstellten Threads niemals Müll gesammelt bekommen.

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"); 
    } 
} 

Antwort

5

Dies ist aufgrund der Tatsache, dass Sie nicht shutdown() auf Ihrem Testamentsvollstrecker Dienst rufen, nachdem Sie Ihre letzte Stelle geplant haben:

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

Habe ich nur noch die shutdown() Anruf und es tritt aus fein. Dies gilt für alle ExecutorService s. Ohne den Shutdown wartet der Thread-Pool weiterhin auf die Übergabe von weiteren Jobs und wird niemals gecallt.

Weitere Details finden Sie unter @ Johns Antwort unten.

3

@Gray ist richtig mit seiner Einschätzung Ich denke nur, ich füge hinzu, warum er richtig ist. Der ExecutorService ist ein Thread-Pool, der die Threads wiederverwendet.

Im Gegensatz new Thread(runnable).start();, wenn die Run-Methode abgeschlossen ist, wird der Thread abgeschlossen und wird dann GC'd. Wenn ein Executor Runnable abgeschlossen ist, wird der Thread dort sitzen und darauf warten, dass eine weitere ausführbare Aufgabe gesendet und verwendet wird. Wenn Sie also herunterfahren, sagen Sie dem Executor, alle Threads im Thread-Pool zu beenden.

Um Ihren letzten Teil zu beantworten. Das Festlegen auf Daemon funktioniert nur, weil keine anderen (Nicht-Daemon-) Threads ausgeführt werden. Wenn Ihre Anwendung einen anderen Nicht-Daemon-Thread gestartet hat, wird der Executor-Thread fortgesetzt. Denken Sie daran, dass ein Daemon-Thread beendet wird, wenn nur Daemon-Threads ausgeführt werden.

+2

Gute info John. Eine Verbesserung. 'shutdown()' beendet nicht alle Threads im Thread-Pool, bis alle Jobs fertig sind. – Gray

+0

@Gray Guter Punkt –

+0

Danke Jungs. Obwohl ich dies zunächst als meine akzeptierte Antwort ausgewählt habe, habe ich später Greys gewählt, weil diese Antwort ohne Gray nicht selbsterklärend ist. Diese Antwort gab mir jedoch die vollständige Erklärung, um den Code mit Sicherheit zu ändern :) und es funktioniert! – Kes115

Verwandte Themen