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

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

问题描述

Apache Tomcat 说了很多次:

Apache Tomcat says many times:

Web 应用程序 [/MyServlet] 似乎已启动名为 [pool-61-thread-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.

以下是如何使用中断停止线程的示例.

确保 executor 被关闭,您可以在 ServletContextListener 中处理这个.

Make sure the executor gets shut down, you can handle this in a ServletContextListener.

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

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