使用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;
}
}
}
答案 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退出。这可能是一个有趣的调试。