Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Servlet "has started a thread but failed to stop it" - memory leak in Tomcat

Apache Tomcat says many times:

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.

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();
like image 639
user3876178 Avatar asked Aug 04 '14 20:08

user3876178


1 Answers

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.

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.

Here's an example of how to stop a thread using interruption.

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

like image 136
Nathan Hughes Avatar answered Sep 19 '22 04:09

Nathan Hughes