Java: Kills thread running as Runnable from ExecutorService

I have a system that starts workers when it receives a call from a web service to do this. The workers are started by the ExecutorService, and the running class implements Runnable. However, if the worker expires, I cannot actually kill the worker, resulting in 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 disconnects, I expect the following log message:

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

      

The service then remains dormant until another request for work is made. However, while calling shutdownNow () and cancel () in ExecutorService and future is more respectable, 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 that you shouldn't do this. However, this is a class that can be extended with the intention of overriding innerCall () - that is, I cannot rely on internalCall on myself and check Thread.isInterrupted () or something.

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

+3


source to share


2 answers


NB

What if the thread does not respond with 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 so the thread returns immediately. Unfortunately, it really isn't any technique that works in general. It should be noted that in all situations where a waiting thread does not respond to Thread.interrupt, it will not respond to Thread.stop. ... cases include intentional denial of service attacks and I / O operations for which thread.stop and thread.interrupt do not work properly. - Primary legacy Java Thread

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

).



What I recommend you for third party code that you cannot trust is also:

  • Run third-party code as the evaluated Java executable language that you control execution. Some examples are rule languages ​​like Drools or logical templating languages ​​like JMustache.

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

+3


source


First, it future.cancel(true)

doesn't kill the current thread. He only tries to stop him from doing it "politely".

What it does is it sends an interrupt signal, more or less, just like you would call yourthread.interrupt()

it somewhere in your code.

It will only stop processing if the code inside the run () method checks for an interrupt. So inside yours, internalCall()

you need to check from time to time if the thread was not interrupted by calling Thread.interrupted()

and stopping execution. Interrupt will also stop sleep (), wait (), IO operations by throwing InterruptedExcepiton (which is why these methods throw such an exception).



ExecutorService

uses the same mechanism, so it will try to interrupt the running threads, but again, if your code does not check for such interruption, the thread will continue to run.

For various reasons, threads shouldn't just be killed (check the java doc for the thread.stop () method and why it's deprecated), but the "generic" way of informing threads that they should probably stop running is by signaling an interrupt.

+1


source







All Articles