What is the correct way to disable threads when tomcat is closed?
I am trying to disconnect threads when Tomcat shuts down.
Specifically, I am trying to disable the log4j watchdog (for file sharing) and also trying to terminate the executor who is using the class in my web application.
On shutdown, I see exceptions in Catalina.out.
For Log4J, I see:
INFO: Illegal Access: This web application instance
has been stopped already. Failed to load org.apache.log4j.helpers.NullEnumeration.
The possible next stack trace is caused by an error caused by debugging and an attempt to terminate the thread that caused the illegal access and has no functional impact. Throwable
happened: java.lang.IllegalStateException
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClassLoader.java:1587)
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClassLoader.java:1546)
on org.apache .log4j.Category.getAllAppenders (Category.java:413)
to org.apache.log4j.Category.closeNestedAppenders (Category.java:226)
at org.apache.log4j.Hierarchy.shutdown (Hierarchy.java:467)
at org.apache.log4j.LogManager.shutdown (LogManager.java:267)
at com.listeners.myListener $ 1.run (myListener.java:232)
Exception on thread "Thread-14" java.lang.NoClassDefFoundError:
org.apache.log4j.helpers.NullEnumeration
at 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.shutdown (LogManager.java:267)
And for the performer part:
INFO: Illegal Access: This web application instance
has been stopped already. Failed to load com.my.class.SomeClass. Ultimately the following stack trace is caused by an error generated to debug and also try to terminate the thread that caused the illegal access and has no functional impact. Thrown: java.lang.IllegalStateException
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClassLoader.java:1587)
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClassLoader)
on thread Exception: 1546 Thread-13 "java.lang.NoClassDefFoundError:
com.my.class.SomeClass
What I am doing is in ServletContextListener
on contextDestroyed
. I added disconnect hooks like this:
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();
}
});
}
What am I doing wrong here? Why am I getting exceptions?
UPDATE: SomeClass.updater
is public static ScheduledExecutorService
.LogManager
org.apache.log4j.LogManager
UPDATE2:
After following the answer from BGR, I do directly
public void contextDestroyed(ServletContextEvent arg0) {
SomeClass.updater.shutdown();
}
and
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
}
I am not getting an exception from Log4j, but I am getting the following exception for SomeClass.updater
which is public static ScheduledExecutorService
:
INFO: Illegal Access: This web application instance
has been stopped already. Failed to load java.util.concurrent.ExecutorService.
a possible subsequent stack trace is caused by an error caused by debugging, as well as attempts to terminate the thread that caused the illegal access and has no functional impact. Throwable
happened: java.lang.IllegalStateException
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClassLoader.java:1587)
on org.apache.catalina.loader.WebappClassLoader.loadClass (WebappClass15Loader ).java:1587
Why? Are the classes already garbage collected?
source to share
I would register the stop hooks in the init () method of the servlet, not contextDetroyed (), but anyway, why would you need to have hooks off in the first place?
Can't you just call SomeClass.updater.shutdown();
directly in the contextDestroyed () method?
EDIT
contextDestroyed()
the listener must be late for the executor service. As stated in the javadoc All servlets and filters will be destroyed before any ServletContextListeners will be notified to destroy the context.
whereas overriding servlet destroy()
should be ok as per the javadoc. This method gives the servlet the ability to clean up any resources that are stored (e.g. memory, manuscript files, streams ...
@Override
public void destroy( ) {
myThreadExecutor.shutdown();
super.destroy( );
}
source to share
Call
LogManager.shutdown();
in context, the destroyed () method is the first step, but the ExecutorService does not close immediately. You get exceptions because the ExecutorService threads are still running after the contextDestroyed () method returns. You need to do:
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
if(LogManager.awaitTermination(10, TimeUnit.SECONDS) == false) {
LogManager.shutdownNow();
}
}
This way the thread pool closed and stopped all threads when contextDestroyed () is called.
source to share