4

I need to time limit a long running function which has zero loops. I run that function using a Callable and call get on the future with a timeout value. AFAIU, future.cancel(true) will set the interrupt flag for the function thread. But until and unless I check and handle Thread.isInterrupted() in longRunningFunction() my code will be unaware that it has to exit and even after shutdownNow() the function will not terminate.

  • How to check for interrupted in longRunningFunction()? The check needs to be prompt i.e if the check is put at specific points then until those points are hit, the thread will not handle the interrupt.
  • Is there any other graceful way to time limit function?
  • Why can't I just kill all threads in executor pool? As per JavaDocs for ExecutorService the pool will never terminate until the threads handle interrupt and terminate themselves.
public class Test {

  public void longRunningFunction() {
    /*
   Long running code without loop
     */
  }

  public Void call() {
    try {
      longRunningFunction()
    } catch (InterruptedException exception) {
      logger.error("{} Error : {}", TAG, exception.getStackTrace().join("\n"))
    } catch (Exception exception) {
      logger.error("[call]{} Error : {}", TAG, exception.getStackTrace().join("\n"))
    }
  }

  public static void main(String[] args) {
    ExecutorService executor = Executors.newSingleThreadExecutor()
    Future<Void> future = executor.submit(new Test())
    int timeoutSeconds = 5
    println "Setting timeout to " + timeoutSeconds
    try {
      future.get(timeoutSeconds, TimeUnit.SECONDS) 
    } catch (TimeoutException e) {
      future.cancel(true)
      logger.error("Could not finish processing within {} seconds", timeoutSeconds)
    } finally {
      executor.shutdownNow()
      executor.awaitTermination(3, TimeUnit.SECONDS)
      logger.error("Shutting down")
    }
  }
}

Edit The question linked for marking duplicate suggests that shared variables are the way to go, which is a known fact as mentioned in the question. The question is to how seamlessly check for that boolean flag i.e Thread.isInterrupted.

ankshah
  • 435
  • 4
  • 20
  • Even if the `longRunningFunction` has no loops is not plausible that there are no intermediate steps inside this function where check for the interrupt flag. – freedev Apr 13 '17 at 11:13
  • Possible duplicate of [How do you kill a thread in Java?](http://stackoverflow.com/questions/671049/how-do-you-kill-a-thread-in-java) – freedev Apr 13 '17 at 11:16
  • The mentioned link suggests that shared variables (the `isInterrupted` flag here) are the way to go. That is a known fact. The question is how to seamlessly check for that boolean variable. – ankshah Apr 13 '17 at 11:21
  • Maybe I'm wrong, but I don't see much alternatives than put into your code few checks for the `isInterrupted` flag. – freedev Apr 13 '17 at 11:23
  • That is a way, but I find that hackish and I want to avoid hacks in a multithreaded code as far as possible (There are multiple various other calls in the method which might run for a long time depending on input) – ankshah Apr 13 '17 at 11:27
  • Ok, I got your idea. So, let's say, what's is the expected behaviour if one of the other long calls is running for long long time? – freedev Apr 13 '17 at 11:30
  • 1
    You say, "no loops." I presume that means no loops _and no recursion_ (i.e., no single place where you can put a statement that will be executed many times during the long run.) And, I presume that it does not call any blocking function, because a blocking function would throw `InterruptedException.` So what's left? How long can a function call take if it has no loops, no recursion, and does not call any blocking functions? – Solomon Slow Apr 13 '17 at 13:10
  • @jameslarge I am downloading a page using BufferedReader.readLine() which [apparently](http://stackoverflow.com/questions/9979485/can-you-interrupt-bufferedreader-readline-with-future-canceltrue) does not throw InterruptedException – ankshah Apr 13 '17 at 13:28
  • @freedev If one of the other long calls is running for long long time I want to throw exception and return control, so that the parent thread can terminate. – ankshah Apr 13 '17 at 13:30
  • 1
    OK, I am officially disqualified from giving out any more Java advice. Looks like there is no way to get an `InterruptedException` when reading from any kind of `InputStream`. Sounds like your `InputStream` was obtained from a `Socket`. What happens if one thread closes the socket while another thread is waiting to receive bytes? – Solomon Slow Apr 13 '17 at 15:38
  • If a single call to `BufferedReader.readLine()` takes a significant amount of time, you should probably manage the buffering yourself so you can check for interruptions at reasonable intervals. – shmosel Apr 14 '17 at 05:58
  • @jameslarge Yes. The `InputStream` is obtained from `HttpUrlConnection`. The socket is not shared among threads. Are you suggesting closing the socket from another thread which will throw an `IOException` where I can do the processing I want to do for `InterruptedException`? – ankshah Apr 14 '17 at 07:57

1 Answers1

1

The only way beyond checking the isInterrupted flag is to kill the thread, control the current state and reconcile it somehow. You can obviously encapsulate this inside a class that makes it appear as the isInterrupted flag has been checked.

snovelli
  • 5,804
  • 2
  • 37
  • 50