Java应用线程泄漏原因分析与避免(2)

/**
    * Should Tomcat attempt to terminate threads that have been started by the
    * web application? Stopping threads is performed via the deprecated (for
    * good reason) <code>Thread.stop()</code> method and is likely to result in
    * instability. As such, enabling this should be viewed as an option of last
    * resort in a development environment and is not recommended in a
    * production environment. If not specified, the default value of
    * <code>false</code> will be used.
    */
    private boolean clearReferencesStopThreads = false;

我猜weblogic也是类似的策略,所以不能指望应用服务器给你清理线程。

应该在什么地方清理线程?

正确的停止应用线程的方法是自己去停止,而不要依赖于应用服务器!

例如,使用spring的,可以利用bean的destroy方法,或者没有spring的,注册一个listener。

public class ContextDestroyListener
        implements ServletContextListener {
 
    @Override
    public void contextInitialized(ServletContextEvent sce) {
    // TODO Auto-generated method stub     
    }
 
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    // TODO Auto-generated method stub
    //在这个地方清理线程
    }
}

我们知道在什么地方去清理这些线程了,接下来就是如何去清理他们了。清理线程并不是加个shutdown方法或者调用一下interrupt那么简单的事情。

如何正确停止线程?

要自己停止线程,首先你得拿到线程的句柄,也就是thread对象或者线程池,如果你写了下面的代码,启动完后你就找不到这个线程了,所以线程一定要在清理线程的时候能拿得到句柄。

public static void main(String[] args) {
    new Thread(new Runnable() {
    @Override
    public void run() {
        while(true) {
        try {
            Thread.sleep(1000);   
        System.out.println("wake up");
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
    }
   
    }).start();
}

正确的方法是把Thread放到一个变量里,例如t,然后通过t去停止这个线程。停止线程的方法一般有stop,destroy,interrupt等,但是stop,destroy都已经被废弃了,因为可能造成死锁,所以通常等做法是使用interrupt。使用interrupt其实类似于信号,就好比你在Linux进程中把SIGTERM信号忽略了,那就没法通过kill杀死进程了,interrupt也是如此。 下面等线程只会报一个异常,中断信号被忽略。

public static void main(String[] args) {
    Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
        while(true) {
        try {
            Thread.sleep(1000);
            System.out.println("wake up");
            } catch(InterruptedException e) {
            e.printStackTrace();
            }
        }
    }
    });
    t.start();
    t.interrupt();//并不能停止线程
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/08bdfa1167151db31faf3977f12dda95.html