2011-01-21 36 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

相关问题