Timeout a callable by another thread or ExecutorService awaitTermination

Default featured post

Timeout a callable by another thread or ExecutorService awaitTermination. In the previous post, here, we discussed how to have a runnable or callable with timeout using ExecutorService. In this post, we optimize the previous solution to be more robust.

When the get method of a future is executed in the main thread, it will get blocked. The main thread has to wait until the future finishes execution or times out. This could be a bad thing in many scenarios.

To avoid that we need to delegate the cancellation task to another thread as it’s discussed below.

Delegating timeout task to another thread

In this approach, we need to schedule a new thread that will start after a certain time and calls of.cancel(true) our callable/runnable. For simplicity sake, let’s call it watcher.

To have our watcher working, we need to switch the executor service implementation from newSingleThreadExecutor() to newScheduledThreadPool(2). The final implementation will be something like below snippet:

As you can see, the only changes are in line 10 and 20. In line 10 we created two threads instead of one. The first one is responsible to run <span class="pl-en">someBlockingTask</span> and the second one is scheduled to cancel the first thread after a certain time. Line 20, is the implementation of our watcher, second thread, that is scheduled to run after 1 second to call.cancel(true) method of the first thread.

The caveat of this approach is if the main thread finishes its execution, it does not wait for the scheduler. Hence, the JVM shutdowns while the task is still running.

One way to mitigate this problem is to use the executor service timeout which is discussed below. Keep in mind that this approach still blocks the main thread but compare with the first example in the previous post is a much better solution.

Leveraging on awaitTermination of the ExecutorService

Executorservice provides awaitTermination method that acts as a timeout clock. It is used with a combination ofshutdown and shutdownNow methods.

But before diving further, let’s focus on the tasks of shutdown and shutdownNow methods.

  • shutdown results in executor service to not accept new tasks but still continues execution of the current tasks in hand.
  • shutdownNow results in executor service to terminate immediately no matter any tasks are running or not.

The implementation would be something like below:

The only difference between the above example and the other example from the previous post is the implementation of setTimeout method.
As you can see, first we call shutdown method so the executor will not accept a new task, even though in this example there is only a single task. Then we wait for one second and after that call shutdownNow() which basically interrupts the task and the task will stop as it’s coded, see line 34.

This approach is a more robust solution compare with the previous one because it blocks the main thread. You just need to keep in mind to not call setTimeout method after creating a method. In the example, for simplicity sake, setTimeout is called after scheduling the task. In a real-world scenario, this should not happen.