Servlet“已经启动了一个线程,但未能阻止它” - Tomcat中的内存泄漏 [英] Servlet "has started a thread but failed to stop it" - memory leak in Tomcat

查看:336
本文介绍了Servlet“已经启动了一个线程,但未能阻止它” - Tomcat中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Apache Tomcat多次说:

Apache Tomcat says many times:


Web应用程序[/ MyServlet]似乎已经启动了一个名为[pool-61-的线程]线程2]但未能阻止它。这很可能会造成内存泄漏。

The web application [/MyServlet] appears to have started a thread named [pool-61-thread-2] but has failed to stop it. This is very likely to create a memory leak.

这有危险吗? servlet应该能够处理10.000个请求/天。
如何在线程结束后关闭线程?

Is this dangerous? The servlet should be able to handle 10.000requests/day. How to close the threads when they have finished?

class Worker {

        private final CountDownLatch startSignal;
        private final CountDownLatch doneSignal;
        private final int threadNumber;

        Worker(
                CountDownLatch startSignal,
                CountDownLatch doneSignal,
                int threadNumber
        ){

            this.startSignal = startSignal;
            this.doneSignal = doneSignal;
            this.threadNumber = threadNumber;

        }

        public String[][] getSomeStrArrArr() {

            String[][] isRs = new String[8][20];
            String[][] inRs = new String[8][20];
            String[][] iwRs = new String[8][20];

            try {

                startSignal.await();

                if (threadNumber == 1) {
                    // get String[][] result for thread number 1
                    isRs = getIS(erg1, erg2, request);

                }

                if (threadNumber == 2) {
                    // get String[][] result for thread number 2
                    inRs = getIN(search_plz, request);
                }

                if (threadNumber == 3) {
                    // get String[][] result for thread number 3
                    iwRs = getIW(erg1, erg2, request);
                }

                doneSignal.countDown();

            } catch (InterruptedException ex) {

                System.out.println(
                        "Thread number "+threadNumber+" has been interrupted."
                );

            }
            if (threadNumber == 1) {
                return isRs;
            }
            if (threadNumber == 2) {
                return inRs;
            }
            if (threadNumber == 3) {
                return iwRs;
            }
            return null;
        }


        public Callable<String[][]> getSomeCallableStrArrArr(){
            return new Callable<String[][]>() {
                public String[][] call() throws Exception {
                    return getSomeStrArrArr();
                }
            };
        }

    }

    ExecutorService pool = Executors.newFixedThreadPool(3);
    Set<Future<String[][]>> set = new HashSet<Future<String[][]>>();
    CountDownLatch startSignal = new CountDownLatch(1);
    CountDownLatch doneSignal = new CountDownLatch(3);
    for (int i=1;i<=3;i++) {
        Worker worker = new Worker(startSignal,doneSignal,i);
        Callable<String[][]> callable =
                worker.getSomeCallableStrArrArr();
        Future<String[][]> future = pool.submit(callable);
        set.add(future);
    }
    startSignal.countDown();
    try {
        doneSignal.await();


推荐答案

是的,这是一个问题。如果您的代码启动非守护程序线程,那么这些线程将继续工作,直到它们退出其run方法。即使其他一切都完成了,旧的JVM也会在这些线程继续运行的时候徘徊。如果你启动一个新实例,那么你可能会遇到旧线程仍然与新实例创建的线程一起工作的情况。

Yes, it's a problem. If your code starts non-daemon threads then those threads will continue working until they exit their run method. Even if everything else finishes, the old JVM will hang around while those threads continue on. If you start up a new instance then you can have a situation where the old threads are still working alongside the ones created by the new instance.

需要设计任务这样他们就会对中断做出反应(而不是吃异常并继续进行,这就是你的例子所示)。这意味着检查当前线程上的中断标志,并以有用的方式捕获InterruptedException,允许任务中断其工作,并在需要时重置中断的标志。 ExecutorService实现有一个shutdownNow方法,它将中断当前任务。

The tasks need to be designed so that they will be responsive to interruption (as opposed to eating the exception and going on, which is what your example shows). That means checking the interrupted flag on the current thread, and catching InterruptedException in a helpful way that allows the task to break its work off and also resets the interrupted flag if needed. ExecutorService implementations have a shutdownNow method that will interrupt the current tasks.

这是一个如何使用中断停止线程的示例

确保执行程序关闭,您可以在ServletContextListener中处理这个问题

这篇关于Servlet“已经启动了一个线程,但未能阻止它” - Tomcat中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆