2

在我的 web 应用程序中,我有 3 个线程,其中 tomcat 无法在重新加载时停止其中的 2 个。

严重:Web 应用程序 [/myapp] 似乎已经启动了一个名为 [Thread-8] 的线程,但未能停止它。这很可能造成内存泄漏。2013 年 5 月 8 日上午 11:22:40 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

这会导致每次重新加载时 CPU 使用率都会上升。

这是tomcat无法停止的线程之一:

在我的 ServletContextListener 中实现的一些代码:

public void contextInitialized(ServletContextEvent event)
{
    final UpdaterThread updaterThread = new UpdaterThread();
    updaterThread.start();
    event.getServletContext().setAttribute("updaterthread", updaterThread);
}

public void contextDestroyed(ServletContextEvent event)
{
    UpdaterThread updaterThread = (UpdaterThread) event.getServletContext().getAttribute("updaterthread");
    if (updaterThread != null)
    {
        updaterThread.stopUpdater();
        updaterThread.interrupt();
        updaterThread = null;
    }
}

以及 UpdaterThread 的重要部分:

public class UpdaterThread extends Thread implements Runnable
{
    private boolean alive = true;

    @Override
    public void run()
    {
        while(true)
        {
            try
            {
                while (alive)
                {
                    doUpdate();
                    sleep(60*1000);
                }
            }
            catch (InterruptedException ie) {}
            catch (Exception e) {}
        }
    }

    public void stopUpdater()
    {
        alive = false;
    }
}

有谁知道为什么这个线程不会停止?有没有更好的方法来实现一个线程在特定时间做一些工作?

4

3 回答 3

5

据我所知,你实际上并没有停止你的线程。您有两个while循环,并且仅在设置时才停止内部循环alive = false。外部将永远运行,什么也不做。您也不处理interrupt您的发送,因此也不会终止线程。

相反,我会做这样的事情:

public void run()
{
    while(alive)
    {
        try
        {
            doUpdate();
            sleep(60*1000);
        }
        catch (InterruptedException ie) {
            alive = false;
        }
    }
} 

此外,如果您在创建线程时为其指定了一个正确的名称,您将查看它是否实际上是导致 Tomcat 报告的问题的线程。

于 2013-05-08T10:36:29.437 回答
1

it’s related to ThreadLocal issues with tomcat, Check this document http://wiki.apache.org/tomcat/MemoryLeakProtection

Mar 16, 2010 11:47:24 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap SEVERE: A web application created a ThreadLocal with key of type [test.MyThreadLocal] (value [test.MyThreadLocal@4dbb9a58]) and a value of type [test.MyCounter] (value [test.MyCounter@57922f46]) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.

http://forum.springsource.org/showthread.php?84202-Installation-ThreadLocal-forcefully-removed

于 2013-05-08T10:41:04.243 回答
0

对您的代码进行小的更改以解决此问题

public class UpdaterThread extends Thread implements Runnable
{
private boolean alive = true;

@Override
public void run()
{
    while(alive)
    {
        try
        {
            doUpdate();
            sleep(60*1000);
        }
        catch (InterruptedException ie) {
          //sleep interrupted
        }
        catch (Exception e) {
          // exception in doUpdate method ? must handle this
        }
    }
}

 public void stopUpdater()
 {
    alive = false;
 }
}

但是,Sleep在 while 循环中可能会产生性能问题。Thread.sleep仅当您想暂停线程一段时间时才可以使用。如果您想等待某些条件,请不要使用它。

检查这个 SO 问题: Thread-sleep-call-in-loop

于 2013-05-08T11:17:16.207 回答