为什么线程执行器本身在关闭后仍然在内存中?

时间:2011-01-21 16:59:25

标签: java multithreading

使用Java和App Server我部署了具有线程执行器的应用程序。

在取消部署期间,我请求执行者关闭。这成功取消了所有任务。但是通过VisualVM,我仍然可以看到一个代表执行者本身的线程,它处于等待状态。我没有保留对执行者的任何引用,因为整个应用程序都被取消部署。因此,如果我多次重复部署 - 取消部署周期,我可以看到线程数如何增长。

我如何摆脱它们?

更新:

代码示例

这是代码:

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 个答案:

答案 0 :(得分:2)

请您详细说明“代表执行者本身的线程”的意思。它的名称/ id / threadgroup是什么?我认为执行者服务不会创建这样的线程。

执行者创建新线程(使用可配置的ThreadFactory)。 Thread自动继承其父级的一些属性,即Thread.currentThread()。但是,在具有部署/取消部署周期的Web应用程序场景中,此行为中最棘手的部分是Thread的ContextClassLoader,它继承自父级的线程。如果ContextClassLoader保留Web应用程序归档中的类,则生成的Executors Thread也将引用此ClassLoader。如果执行者执行的代码具有例如使用WebappClassLoader中的类的ThreadLocals,您可能会遇到ClassLoader泄漏问题。

答案 1 :(得分:1)

需要使用方法shutdown显式停止执行程序,否则它会像你发现的那样徘徊。您可以从javadoc中看到Executors.newSingleThreadExecutor它包含一个工作线程。

shutdownNow的javadoc说:

  

除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此如果任何任务屏蔽或无法响应中断,它们可能永远不会终止。

如果正在执行的任务没有响应中断(在没有退出的情况下吞下InterruptedExceptions),那么这将导致执行程序永远不会被关闭。任何未明确关闭的非守护程序线程都会挂起并阻止JVM退出。这可能是一个有趣的调试。