2012-05-17 43 views
5

請幫我看下面代碼中線程泄漏的原因。即使在run()完成後(從安慰的打印語句驗證)並且主方法已退出(從打印語句和分析器工具驗證),TestThread也不會收集垃圾回收。爲什麼運行ScheduleExecutorService的UserThread不會被垃圾收集

但是,如果TestThread設置爲守護程序線程,即t.setDaemon(true),則會收集垃圾回收。下面的代碼只是一個示例代碼,它說明了我的應用程序中的問題。我正在嘗試使用一些預先存在的日程安排類(由其他人使用ScheduledExecutorService設計)。我注意到,當我保持與類的多個Runnable s時,創建的線程永遠不會收集垃圾。

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

回答

5

這是由於這樣的事實,你是不是要求您執行服務shutdown()已計劃後,你的上一份工作:

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

我剛添加的shutdown()調用你的代碼,並退出精細。在所有ExecutorService s中都是如此。如果沒有關閉,線程池將繼續等待更多的作業提交併且從不GC'd。

請參閱下面的@ John的答案以獲取更多詳細信息。

3

@格雷對他的評估是正確的我只是想補充他爲什麼是正確的。 ExecutorService是一個將重用線程的線程池。

new Thread(runnable).start();不同於當run方法完成線程完成,之後將GC'd。當Executor Runnable完成時,線程將坐在那裏等待另一個可運行的任務被提交和使用。所以通過關閉,你告訴執行者結束線程池中的所有線程。

回答你最後的部分。將其設置爲守護進程僅僅是因爲沒有其他(非守護進程)線程在運行。如果你的應用程序啓動了一些其他的非守護線程,Executor線程將繼續。記住守護進程線程在只有守護進程線程運行時會被終止。

+2

好信息約翰。一個調整。 'shutdown()'不會結束線程池中的所有線程,直到所有作業已提交完成。 – Gray

+0

@格雷好點 –

+0

謝謝你們。雖然我最初選擇這個作爲我接受的答案,但後來我選擇了格雷的答案,因爲如果沒有格雷的答案,這個答案就不言自明。但是,這個迴應給了我充分的解釋,需要有信心修改代碼:)並且它可以工作! – Kes115