停止Tomcat

时间:2016-10-25 09:50:36

标签: java multithreading tomcat executorservice

我想要在服务器关闭时停止ExecutorService executor = Executors.newSingleThreadExecutor();

我有一个implements ServletContextListener的课程,并注明了@WebListener

我在该课程中有两种方法:

@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    System.out.println("ServletContextListener started");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    executor.shutdown();
    executor.shutdownNow();
    System.out.println("ServletContextListener destroyed");
}

而且我看到它在它们应该的时候打印出它们中的内容,但当我在intelij中按下一次停止按钮时,我得到:

  

严重:Web应用程序[]似乎已启动名为[pool-2-thread-1]的线程但未能停止它。这很可能会造成内存泄漏。

打印后ServletContextListener destroyed

我需要再次按下停止按钮才能完全停止它。

为什么它不会关闭ExecutorService,即使它已到达executor.shutdown();?我做错了什么?

PS:这是我唯一的ExecutorService,我没有其他线程。

EDIT2:

执行程序服务是单例类中的一个字段,它使用类初始化:

private ExecutorService executor = Executors.newSingleThreadExecutor();

这是类的初始化方式(延迟初始化):

public static RoomsManager getRoomsManager(ServletContext servletContext) {
    if (servletContext.getAttribute(MANAGER_GAMES_ATTRIBUTE_NAME) == null) {
        servletContext.setAttribute(MANAGER_GAMES_ATTRIBUTE_NAME, new RoomsManager());
    }
    return (RoomsManager)servletContext.getAttribute(MANAGER_GAMES_ATTRIBUTE_NAME);
}

并注释如下:

@WebListener
public class RoomsManager  implements ServletContextListener {

停止按钮是intelij IDEA中播放和调试按钮附近的红色方块。

2 个答案:

答案 0 :(得分:2)

问题是你有两个不同的RoomsManager个实例(因此有两个不同的执行器):第一个是由Tomcat创建的,第二个是由你创建的。

当您使用RoomsManager注释@WebListener时,Tomcat会自动创建该类的实例并订阅它以接收servlet上下文创建/销毁事件。该实例是实际停止其执行者并打印ServletContextListener destroyed的实例。

第二个实例是由您在getRoomsManager方法中创建的(顺便说一句,该方法看起来不是线程安全的)。该实例未在Tomcat中注册,并且未接收到servlet上下文“destroy”事件,因此它甚至不会尝试关闭其执行程序。

答案 1 :(得分:1)

这样做有效:

class YourThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
        return new Thread(r, "Your name");
    }
}
private ExecutorService executor = Executors.newSingleThreadExecutor(new YourThreadFactory());

因为很明显,tomcat的线程是守护进程,因此,当他们用return new Thread(r, "Your name");创建一个新线程时,它也会成为一个守护进程。

但是在执行程序服务使用的DefaultThreadFactory中,我看到它确保关闭新线程的守护程序。

这并不能解释executor.shutdown();为什么不起作用,但现在至少它已正常关闭。