1

I've been searching web for a week now but none of the posts like How do I get FutureTask to return after TimeoutException? seems to answer my question. I've extracted a code sample from my code:

 Future<Object> result = executorService.submit(new Callable<Object>() {
    @Override public Object call() throws Exception {
     ...........
    }
  });

  try {
    return result.get(timeout.getValue(), timeout.getUnit().getTimeUnit());
  } catch (TimeoutException e) {
    result.cancel(true);
    throw new TTimeoutException(e);
  }

If I run this, sometimes(1 out of 1000) I'm getting

 java.lang.InterruptedException
        at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:400)
        at java.util.concurrent.FutureTask.get(FutureTask.java:199)
        at com.abc.callers.A.call(A.java:83)

and line no:83 is result.get() of future task shown in above code sample.

Now my question is, can calling result.cancel(true) in future cause InterruptedException in result.get? If not, who can change the interrupt status of my current thread? AFAIK result.get() isn't the same thread as the one running my submitted task which I'm cancelling..

Community
  • 1
  • 1
Heisenberg
  • 5,514
  • 2
  • 32
  • 43
  • 1
    Cancel should not be causing the InterruptedException as the line number indicates a call to result.get(). – Andy Dufresne Nov 27 '14 at 13:43
  • @AndyDufresne No, that's the call stack from the thread that got interrupted. It doesn't tell you where the interrupt came from. – chiastic-security Nov 27 '14 at 13:44
  • @AndyDufresne: I wouldn't be so sure about that since exceptions that occur in future threads get channeled to the `get()` method call. That is one reason why this method **should** be called even if it returns nothing. – Hovercraft Full Of Eels Nov 27 '14 at 13:44
  • @HovercraftFullOfEels - Correct me if my understanding is incorrect - The code snippet above is missing the catch block for InterruptedException, but assuming it is the same as TimeOutException, how can result.cancel() method call cause an interrupt in the same thread? – Andy Dufresne Nov 27 '14 at 13:52
  • @AndyDufresne: per the [FutureTask API](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html), if an InterruptedException is thrown during the running of the FutureTask, it will be thrown when `get()` is called, meaning it will be thrown in the thread that `get()` is called which is usually not the same thread as the FutureTask. – Hovercraft Full Of Eels Nov 27 '14 at 14:05
  • @HovercraftFullOfEels an `InterruptedException` from inside the task will appear as `ExecutionException`, `InterruptedException` from `get()` means that the (get-) calling thread was interrupted. http://ideone.com/zTL1Nq – zapl Nov 27 '14 at 14:17
  • @zapl: yes the interrupt exception will be wrapped inside of an ExecutionException. – Hovercraft Full Of Eels Nov 27 '14 at 14:26
  • Interesting.. You can get to an interrupted exception in a way through using cancel(true), http://ideone.com/Fy4AJU - the same code however causes a `CancellationException` for me locally. Something must have changed in the implementation of `get()` in prioritizing cancellation over interrupts?! – zapl Nov 27 '14 at 15:15
  • 1
    From the piece of code you have posted, it is impossible to get the `InterruptedException` as a result of `cancel` as you don’t call `cancel` when an `InterruptedException` is thrown. Or the other way round, if you call `cancel` within the `catch (TimeoutException…` block, you can’t get an `InterruptedException` in `get` as `get` already completed with a `TimeoutException`. Obviously, the cause for the `InterruptedException` lies in a piece of code you did *not* post here. – Holger Dec 01 '14 at 14:17

2 Answers2

2

From the Javadoc:

boolean cancel(boolean mayInterruptIfRunning)

Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

After this method returns, subsequent calls to isDone() will always return true. Subsequent calls to isCancelled() will always return true if this method returned true.

So if mayInterruptIfRunning is set, then yes, it will attempt to interrupt the thread running the task.

In other words, .cancel(true) will attempt to interrupt a running task, and .cancel(false) won't.

It sounds as though result.get() will still get interrupted if you call .cancel(false) and the task hasn't even started.

Community
  • 1
  • 1
chiastic-security
  • 20,430
  • 4
  • 39
  • 67
  • I've read this already. But as I checked out the code of awaitDone it's checking Thread.interrupted() that means current thread and not the runner thread which result.cancel() will interrupt. – Heisenberg Nov 27 '14 at 13:44
1

Thanks for your inputs everyone. After so much digging I finally found the answer.

This is a server side code and the fault was in client code who was interrupting server if it was not returning result in specified time limit. Of course client's time limit was less than server's timeout limit.

Although they were catching the interrupted exception thrown from server, but this was wrapped under UndeclaredThrowableException as server was using dynamic proxies.

Heisenberg
  • 5,514
  • 2
  • 32
  • 43