@H_404_1@我有一个ExecutorService executor = Executors.newSingleThreadExecutor();我想在服务器关闭时停止.
@H_404_1@我有一个实现ServletContextListener的类,它用@WebListener注释.
@H_404_1@我在该课程中有两种方法:
@H_404_1@
@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");
}
@H_404_1@而且我看到它在它们应该的时候打印出它们中的内容,但是当我在intelij中按下一次停止按钮时,我得到:
@H_404_1@
@H_404_1@SEVERE: The web application [] appears to have started a thread named [pool-2-thread-1] but has Failed to stop it. This is very likely to create a memory leak.@H_404_1@在它打印出ServletContextListener之后就被销毁了. @H_404_1@我需要再次按下停止按钮才能完全停止它. @H_404_1@为什么它不会关闭ExecutorService,即使它到达executor.shutdown();?我究竟做错了什么? @H_404_1@PS:这是我唯一的ExecutorService,没有其他线程由我制作. @H_404_1@EDIT2: @H_404_1@执行程序服务是单例类中的一个字段,它使用类初始化: @H_404_1@
private ExecutorService executor = Executors.newSingleThreadExecutor();
@H_404_1@这是类的初始化方式(延迟初始化):
@H_404_1@
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);
}
@H_404_1@并注释如下:
@H_404_1@
@WebListener
public class RoomsManager implements ServletContextListener {
@H_404_1@停止按钮是intelij IDEA中播放和调试按钮附近的红色方块.最佳答案
问题是你有两个不同的RoomsManager实例(因此有两个不同的执行器):第一个是由Tomcat创建的,第二个是由你创建的.
@H_404_1@当您使用@WebListener注释RoomsManager时,Tomcat会自动创建该类的实例并订阅它以接收servlet上下文创建/销毁事件.该实例是实际停止其执行程序并打印ServletContextListener的实例.
@H_404_1@第二个实例是由您在getRoomsManager方法中创建的(顺便说一下,该方法看起来不是线程安全的).该实例未在Tomcat中注册,并且未接收servlet上下文“destroy”事件,因此它甚至不会尝试关闭其执行程序.