2011-01-21 61 views
3

使用Java和App Server我部署具有線程執行器的應用程序。爲什麼線程執行程序本身在關閉後仍在內存中?

在部署過程中,我請求執行器關閉。這成功取消了所有的任務。然而,通過VisualVM,我仍然可以看到一個表示執行器本身的線程,它處於等待狀態。在整個應用程序取消部署時,我不保留對執行器的任何引用。所以如果我多次重複部署 - 非部署週期,我可以看到線程數量如何增長。

我該如何擺脫它們?

UPDATE:

代碼示例

這裏是代碼:

public void startScheduler() 
{ 
    if (scheduledExecutor == null) 
    { 
     scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("My ScheduledExecutor")); 
     processFuture = scheduledExecutor.scheduleAtFixedRate(new Runnable() 
      { 
       @Override 
       public void run() 
       { 
        startProcessor(); 
       } 
      }, 0, 84600, TimeUnit.SECONDS); 
    } 
} 


public void stopScheduler() 
{ 

    if (processFuture != null) 
    { 
     processFuture.cancel(true); 
     processFuture = null; 
    } 

    if (scheduledExecutor != null) 
    { 
     try 
     { 
      scheduledExecutor.shutdownNow(); 
      scheduledExecutor.awaitTermination(10, TimeUnit.SECONDS); 
     } 
     catch (InterruptedException ignored) 
     {} 
     finally 
     { 
      scheduledExecutor = null; 
     } 
    } 

} 
+2

您使用的具體Executor類是什麼?你打的什麼確切的關機方法? – richs

+0

Executors.newSingleThreadScheduledExecutor和shutdownNow() – user567068

+0

這段代碼是正確的。如果執行者被關閉,那麼問題在於別處。 – jtahlborn

回答

2

能否請您詳細說明你的意思 「表示執行器本身就是一個線程」 是什麼。它是什麼名稱/編號/線程組?我不認爲執行者服務創建了這樣一個線程。

執行程序創建新線程(使用可配置的ThreadFactory)。一個線程會自動繼承它的父對象的一些屬性,即Thread.currentThread()。但是,在具有deploy/undeploy循環的Web應用程序方案中,此行爲中最有問題的部分是Thread的ContextClassLoader,它從父級的線程繼承。如果您的ContextClassLoader在您的Web應用程序歸檔中保留了類,那麼生成的Executors Thread也會引用此ClassLoader。如果由執行者執行的代碼具有例如ThreadLocals帶有來自WebappClassLoader的類,您可能會遇到ClassLoader泄漏問題。

+0

更新了代碼。 startScheduler()在部署時調用,stopScheduler()在部署時調用。在VisualVM中,我看到「My ScheduledExecutor」線程。我認爲你一定是對的,因爲我們使用自制應用程序裝載器來承擔集裝箱的一些責任,所以這是泄漏。 (如加載類)。關機代碼看起來是否正確?或者還有什麼可以做的,比如可能取消註冊CalssLoader的引用......謝謝! – user567068

+0

執行代碼看起來不錯,我用測試用例進行了驗證。要找到泄漏點,請執行許多重新部署並進行堆轉儲。然後,從所有Thread(「My ScheduledExecutor」)對象中查找GC根的路徑。我敢打賭你會找到WebappClassLoaders。使用Eclipse MAT和「Group By ClassLoader」。 – mhaller

1

執行程序需要使用方法shutdown明確停止,否則它將像您發現的那樣掛起。您可以從javadoc中看到Executors.newSingleThreadExecutor它包含一個工作線程。

的shutdownNow時的Javadoc說:

有沒有保證盡最大努力,試圖積極停止處理執行任務。例如,典型的實現將通過Thread.interrupt()取消,所以如果任何任務屏蔽或無法響應中斷,它們可能永遠不會終止。

如果正在執行的任務沒有響應中斷(吞下InterruptedExceptions而不會退出),那麼這會導致您的執行程序永遠不會關閉。任何沒有明確關閉的非守護進程線程都會停留並阻止JVM退出。這可能是一個有趣的調試。

+0

我使用shutdownNow,甚至等待它一點點... – user567068

+0

當我解除應用程序的線程處於等待狀態時,現在應該有任何「吞嚥」InterruptedExceptions,這將阻止它正常關閉。 – user567068

相關問題