Java Multithreading – How to Interrupt a Specific Thread of an ExecutorService

executorservicejavamultithreading

If I have an ExecutorService to which I feed Runnable tasks, can I select one and interrupt it?
I know I can cancel the Future returned (also mentioned Here: how-to-interrupt-executors-thread), but how can I raise an InterruptedException. Cancel doesn't seem to do it (event though it should by looking at the sources, maybe the OSX implementation differs). At least this snippet doesn't print 'it!' Maybe I'm misunderstaning something and it's not the custom runnable that gets the exception?

public class ITTest {
static class Sth {
    public void useless() throws InterruptedException {
            Thread.sleep(3000);
    }
}

static class Runner implements Runnable {
    Sth f;
    public Runner(Sth f) {
        super();
        this.f = f;
    }
    @Override
    public void run() {
        try {
            f.useless();
        } catch (InterruptedException e) {
            System.out.println("it!");
        }
    }
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService es = Executors.newCachedThreadPool();
    Sth f = new Sth();
    Future<?> lo = es.submit(new Runner(f));
    lo.cancel(true); 
    es.shutdown();
}

}

Best Answer

The right thing to do here is to cancel the Future. The issue is that this will not necessarily cause an InterruptedException.

If the job has yet to run then it will be removed from the runnable queue -- I think this is your problem here. If the job has already finished then it won't do anything (of course). If it is still running then it will interrupt the thread.

Interrupting a thread will only cause sleep(), wait(), and some other methods to throw InterruptedException. You will also need test to see if the thread has been interrupted with:

if (Thread.currentThread().isInterrupted()) {

Also, it is a good pattern to re-set the interrupt flag if you catch InterruptedException:

try {
   Thread.sleep(1000);
} catch (InterruptedException e) {
   // this is a good pattern otherwise the interrupt bit is cleared by the catch
   Thread.currentThread().interrupt();
   ...
}

In your code, I would try putting a sleep before you call lo.cancel(true). It may be that you are canceling the future before it gets a chance to execute.