tomcat关闭时关闭线程的正确方法是什么?

Jim*_*Jim 5 multithreading tomcat servlets log4j web-applications

我试图在关闭 Tomcat 时关闭线程。
具体来说,我正在尝试关闭 log4j 看门狗(用于文件更改),并且我正在尝试关闭使用我的 Web 应用程序中的类的执行程序。
关闭时,我在 Catalina.out 中看到异常。
对于 Log4J,我看到:

信息:非法访问:此 Web 应用程序实例已停止
。无法加载 org.apache.log4j.helpers.NullEnumeration。
最终的后续堆栈跟踪是由出于
调试目的抛出的错误以及尝试终止
导致非法访问的线程引起的,并且没有功能影响。Throwable
发生:java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at org.apache .log4j.Category.getAllAppenders(Category.java:413)
在 org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
在 org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
在 org.apache.log4j.LogManager.shutdown(LogManager.java:267) )
在 com.listeners.myListener$1.run(myListener.java:232)
线程“Thread-14”中的异常 java.lang.NoClassDefFoundError:
org.apache.log4j.helpers.NullEnumeration
在 org.apache.log4j.Category.getAllAppenders (Category.java:413)
at org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
at org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
at org.apache.log4j.LogManager。关机(LogManager.java:267)

对于执行者部分:

信息:非法访问:此 Web 应用程序实例已停止
。无法加载 com.my.class.SomeClass。最终的
后续堆栈跟踪是由出于调试
目的抛出的错误以及尝试终止导致
非法访问的线程引起的,并且没有功能影响。Throwable发生:
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at Exception in thread “线程 13” java.lang.NoClassDefFoundError:
com.my.class.SomeClass

我做的是ServletContextListenercontextDestroyed我加入关闭挂钩如下:

public void contextDestroyed(ServletContextEvent arg0) {  

         Runtime.getRuntime().addShutdownHook(new Thread(){  
            @Override  
            public void run(){  
                LogManager.shutdown();                  
            }  
         });  

    } 





 public void contextDestroyed(ServletContextEvent arg0) {  

        Runtime.getRuntime().addShutdownHook(new Thread(){  
            @Override  
            public void run(){  
                SomeClass.updater.shutdown();  
            }  
        });  

    }  
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么?为什么会出现异常?

更新:
SomeClass.updater是一个public static ScheduledExecutorService.
LogManagerorg.apache.log4j.LogManager

UPDATE2:
按照 BGR 的回答后,我直接做

public void contextDestroyed(ServletContextEvent arg0) {  

            SomeClass.updater.shutdown();  

        }  
Run Code Online (Sandbox Code Playgroud)

public void contextDestroyed(ServletContextEvent arg0) {  

                LogManager.shutdown();                  

        } 
Run Code Online (Sandbox Code Playgroud)

我没有从 Log4j 得到异常,但我得到以下异常,SomeClass.updater它是一个public static ScheduledExecutorService

信息:非法访问:此 Web 应用程序实例已停止
。无法加载 java.util.concurrent.ExecutorService。该
最终以下堆栈跟踪被抛出的错误造成的
调试目的,以及试图终止该线程
引起的非法访问,并没有功能的影响。Throwable
发生:
在 org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
在 org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546) 的 java.lang.IllegalStateException

为什么?这些类是否已经被垃圾收集了?

Bru*_*der 3

我会在 servlet 的 init() 方法中注册 shutdown hooks,而不是 contextDetroyed(),但无论如何,为什么首先需要 Shutdown hooks?

SomeClass.updater.shutdown();直接在contextDestroyed()方法中调用不行吗?

编辑

contextDestroyed()侦听器的执行器服务太迟了。正如 javadoc 中所述,在任何 ServletContextListener 收到上下文销毁通知之前,所有 servlet 和过滤器都将被销毁。

destroy()而根据 javadoc重写 servlet应该没问题。此方法使 servlet 有机会清理所持有的任何资源(例如,内存、文件句柄、 线程...

@Override
public void destroy(  ) {


        myThreadExecutor.shutdown();

        super.destroy(  );
}
Run Code Online (Sandbox Code Playgroud)