Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Killing a thread launched as a Runnable by ExecutorService

I have a system which launches workers when it receives a call from a webservice to do so. The workers are launched by an ExecutorService, the class being launched implements Runnable. However, if the worker times out, I am unable to actually kill the worker, which is leading to resource issues on my system.

public class MyClass implements Runnable {

    public void internalCall() {
        logger.info("B-1");
        //Some business code which may take too long
        // <...>
        logger.info("B-2");
    }

    public void launch() {
        // Wrapper
        Callable<Object> callable = new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                internalCall();
                return null;
            }
        };

        // Submit
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Object> future = executor.submit(callable);

        try {
            // Wait
            future.get(1, TimeUnit.SECONDS);
        }
        catch (TimeoutException e) {
            logger.warn("Timeout");
        }
        finally {
            logger.info("A-1");
            executor.shutdownNow();
            future.cancel(true);
            logger.info("A-2");
        }
    }
}

If the worker times out, I would expect the following log message:

INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2

Followed by the service remaining idle until another worker request comes in. However, despite calling shutdownNow() and cancel() on the ExecutorService and Future respectably, the worker continues:

INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
INFO | B-2

I've looked around and there are a number of other, similar questions about killing threads, with the general consensus being that you shouldn't do it. However, this is a class which may be extended, with the intent to override the internalCall() - meaning I can't rely on internalCall to police itself and check Thread.isInterrupted() or anything like that.

I'd like to just force kill things from the launch() method by attacking the furure or executor object.

like image 612
tim Avatar asked Oct 24 '25 16:10

tim


1 Answers

N.B.

What if a thread doesn't respond to Thread.interrupt?

In some cases, you can use application specific tricks. For example, if a thread is waiting on a known socket, you can close the socket to cause the thread to return immediately. Unfortunately, there really isn't any technique that works in general. It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either. Such cases include deliberate denial-of-service attacks, and I/O operations for which thread.stop and thread.interrupt do not work properly. - Java Thread Primitive Deprecation

So what have we learned... In Java do not run third party code that you really can't trust in the same execution as your primary application. Also even if Thread.stop did work you still have a whole bunch of other things that are far worse than threads not checking interrupt status (ie code calling System.exit(0)).

What I recommend you do for third party code that you can't trust is either:

  • Run the third party code as an evaluated language run by Java that you control the execution of. Some examples are: rules languages like Drools or logicless templating language like JMustache.

  • Run the third party code in a separate execution and use your operating system to kill the process and IPC such as sockets for communication.

like image 185
Adam Gent Avatar answered Oct 26 '25 04:10

Adam Gent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!