如何在Java中识别和删除从我们的webapp启动的线程/线程本地程序?

如何在Java中识别和删除从我们的webapp启动的线程/线程本地程序?,java,multithreading,tomcat7,thread-local,Java,Multithreading,Tomcat7,Thread Local,每当我停止或重新部署webapp时,我都会看到很多类似的错误 msg=The web application [] created a ThreadLocal with key of type [] (value []) and a value of type [] (value []) but failed to remove it when the web application was stopped. Threads are going to be renewed over time

每当我停止或重新部署webapp时,我都会看到很多类似的错误

msg=The web application [] created a ThreadLocal with key of type [] (value []) and 
a value of type [] (value []) but failed to remove it when the web application was 
stopped. Threads are going to be renewed over time to try and avoid probable memory leak
我没有在我的应用程序中创建任何ThreadLocals,而是引用了许多可能正在创建这些ThreadLocals的库。我们目前正在使用Tomcat7。我已经讨论过其他类似的问题,但所有这些问题都只是建议这是Tomcat的特性,用于警告您不要删除ThreadLocals。我看不到任何解决办法。我还看到一些关于线程未停止的错误

msg=The web application [] appears to have started a thread named [] but has
failed to stop it. This is very likely to create a memory leak.
在我们公司的中央日志系统中,这些错误被作为错误登录,从而增加了应用程序的错误计数。当我们检查应用程序的性能时,这看起来肯定不好。我尝试了这两个源代码的实现,并从中获得了示例代码,但似乎不起作用。它删除了不是由我们的应用程序创建的线程/线程局部变量我需要的是只删除由我们的webapp启动的线程/线程局部变量。在ServletContextListener的contextDestroyed()方法中,有什么方法可以删除这些吗?下面是我当前的ServletContextListener类

公共类CustomServletContextListener实现ServletContextListener{
私有列表启动;
@凌驾
public void contextInitialized(ServletContextEvent sce){
retrieveThreadsOnStartup();
}
@凌驾
公共无效上下文已销毁(ServletContextEvent sce){
//现在,在该上下文的类加载器中注销JDBC驱动程序:
//获取webapp的类加载器
ClassLoader cl=Thread.currentThread().getContextClassLoader();
//循环遍历所有驱动程序
枚举驱动程序=DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver-Driver=drivers.nextElement();
if(driver.getClass().getClassLoader()==cl){
//此驱动程序已由webapp的ClassLoader注册,因此请取消注册:
试一试{
println(“取消注册JDBC驱动程序{}:“+driver”);
DriverManager.deregisterDriver(驱动程序);
}catch(SQLException-ex){
System.out.println(“取消注册JDBC驱动程序{}时出错:“+driver+”\n异常:“+ex”);
}
}否则{
//驱动程序未由webapp的类加载器注册,可能正在其他地方使用
println(“不注销JDBC驱动程序{},因为它不属于这个webapp的类加载器:“+driver”);
}
}
//线程
ThreadGroup ThreadGroup=Thread.currentThread().getThreadGroup();
threadGroup=Thread.currentThread().getThreadGroup();
线程[]线程;
试一试{
线程=retrieveCurrentActiveThreads(线程组);
}捕获(无此字段例外){
System.out.println(“无法检索初始线程列表。关闭时应用程序可能不稳定”+e.getMessage());
返回;
}捕获(非法访问例外e){
System.out.println(“无法检索初始线程列表。关闭时应用程序可能不稳定”+e.getMessage());
返回;
}
int toBeKilledCount=0;
int totalThreadCount=0;
int killedTLCount=0;
int totalTLCount=0;
int killedITLCount=0;
int totalITLCount=0;
对于(;totalThreadCountLogManager.shutdown()
DriverManager.deregisterDriver(driver);
private void cleanThreadLocals() {
    try {
        // Get a reference to the thread locals table of the current thread
        Thread thread = Thread.currentThread();
        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        Object threadLocalTable = threadLocalsField.get(thread);

        // Get a reference to the array holding the thread local variables inside the
        // ThreadLocalMap of the current thread
        Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
        Field tableField = threadLocalMapClass.getDeclaredField("table");
        tableField.setAccessible(true);
        Object table = tableField.get(threadLocalTable);

        // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
        // is a reference to the actual ThreadLocal variable
        Field referentField = Reference.class.getDeclaredField("referent");
        referentField.setAccessible(true);

        for (int i=0; i < Array.getLength(table); i++) {
            // Each entry in the table array of ThreadLocalMap is an Entry object
            // representing the thread local reference and its value
            Object entry = Array.get(table, i);
            if (entry != null) {
                // Get a reference to the thread local object and remove it from the table
                ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
                threadLocal.remove();
            }
        }
    } catch(Exception e) {
        // We will tolerate an exception here and just log it
        throw new IllegalStateException(e);
    }
}
Runtime.getRuntime().addShutdownHook(webapp.new ShutdownHook());