Proper way to handle Thread.interrupted() in a Callable?

Greg Brown picture Greg Brown · Oct 9, 2012 · Viewed 7.2k times · Source

What is the proper way to handle Thread.interrupted() in a Callable? I'm guessing that the callable should throw an InterruptedException; for example:

public class MyCallable implements Callable<Object> {
    public Object call() {
        Object result = null;

        // Simulate long-running operation that calculates result
        while (true) {
            ...
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        }

        result = ... // something produced by the long-running operation    

        return result;
    }
}

Is this correct, or is there a more appropriate way to handle it? Thanks.

Answer

Gray picture Gray · Oct 9, 2012

Edit:

After some back and forth, it seems like you want to be able to interrupt your IO routines. This seems like a good job for some of the NIO InterrutibleChannel classes. For example, reading from the following BufferedReader is interruptible and will throw InterruptedIOException. See here for more examples of the NIO code.

BufferedReader in = new BufferedReader(new InputStreamReader(
    Channels.newInputStream((new FileInputStream(
        new File(...))).getChannel())));

Then, you can call future.cancel() which will interrupt your thread and cause the IO to throw a InterruptedIOException. If that happens, you could not catch the IOException and let it trickle out of the call() method.


If you want to pass back to the Future that the call() method was interrupted then I think throwing InterruptedException is fine. Another option would be to just return null; or some other marker object from your call() method instead. That's typically what I do if a thread was interrupted.

One thing to remember is that if call() throws InterruptedException, when you do a future.get() it will throw a ExecutionException and the cause of that exception is going to be an InterruptedException. Don't be confused that future.get() can also throw a InterruptedException itself if the get(long timeout, TimeUnit unit) times out.

 try {
     result = future.get();
 } catch (ExecutionException e) {
     if (e.getCause() instanceof InterruptedException) {
        // call() method was interrupted
     }
 } catch (InterruptedException e) {
     // get was interrupted
 }

If, however, future.cancel(true) was called then the future.get() will throw a CancellationException instead.