1

Why doesn't setting the interrupt bit in a Callable cause the Future that represents the Callable to throw a TimeoutException when Future.get() is called?

public class ExecutorServiceTest extends MockitoTestCase {
  private static CountDownLatch latch1 = new CountDownLatch(1);

  class TaskChecksForInterruptedExcAndDoesSetInterruptedBit implements Callable<String> {
    @Override
    public String call() {
      latch1.countDown();
      while (!Thread.currentThread().isInterrupted()) {
      }
      Thread.currentThread().interrupt();
      return "blah";
    }
  }

  void testInterrupt() throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(numThreads);
    Future<String> future = pool.submit(new TaskChecksForInterruptedExcAndDoesSetInterruptedBit());
    latch1.await(); // Don't interrupt the Callable until it actually starts processing
    pool.shutdownNow();
    try {
      future.get(100, TimeUnit.MILLISECONDS);
    } catch (final TimeoutException e) {
      // Why doesn't this get called!
      return;
    }
    fail();
  }
}
Chris Morris
  • 4,335
  • 4
  • 24
  • 28

1 Answers1

1
  1. the shutdownNow() call attempts to interrupt all running tasks. In this case the interruption is detected in your busy loop, so the code continues and the Callable returns "blah" (and not an exception)

  2. TimeoutException, according to the spec, is thrown only if the thread waits for the complete timeout period, but no result becomes available. Interruption doesn't fit into this scenario.

  3. Your usage of CountDownLatch is incorrect. You decrement it, but I see no call to latch1.await()

Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78
  • I fixed the CountDownLatch, by the way. – Chris Morris Mar 04 '13 at 19:09
  • So when does Future.get() return TimeoutException? Only when the Callable hasn't returned by specified timeout length? Something else I just thought of, why wouldn't Future.get() thrown an InterruptedException since the spawned Thread's interrupt bit gets set? – Chris Morris Mar 04 '13 at 19:11
  • Yes, the TimeoutException in future.get(..) happens only when the full timeout period ellapses. The only case where InterruptedException can be thrown by future.get() is when the thread blocked on the get(..) is interrupted by another thread. It has nothing to do with the state of the background thread running your callable. – Eyal Schneider Mar 04 '13 at 19:15
  • Ok. I didn't know if, somehow, calling Future.get() would check to see if the background thread had been interrupted, and thrown an InterruptedException in that case. I guess it doesn't. – Chris Morris Mar 04 '13 at 19:16
  • future.get() can throw other kinds of exceptions as well. In case that the background thread terminates with an exception, then you'll get an ExecutionException wrapping the original exception. – Eyal Schneider Mar 04 '13 at 19:17
  • Following my last comment: if you did an interruptible blocking operation inside the callable thread (such as sleep or wait), then this interruption would have caused an InterruptedException to be wrapped by an ExecutionException and thrown in the main thread. – Eyal Schneider Mar 04 '13 at 19:24
  • thanks. Here's a related question I just created: http://stackoverflow.com/questions/15209583/why-set-the-interrupt-bit-in-a-callable – Chris Morris Mar 04 '13 at 19:33