Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to interrupt a Future, but still wait for it to finish?

I have series of jobs that I queue up using an ExecutorService. If the user clicks 'cancel', then I need to notify those jobs that they should stop as soon as possible. However, sometimes they are in critical sections of code that must complete before the parent thread should proceed. How can I do this? I don't want to use my own cancel flag, because that won't cause sleep/wait to exit.

I thought this code would work, but it doesn't do what I want:

while( true ) {
    //Do this in a loop. If our thread is interrupted, we call cancel on the threads (to try to get them to hurry up by skipping non-essential stuff), but we still need to wait for them to finish.
    try {
        for( Future<Void> future : futures ) {
            future.get(); //I thought that this would continue waiting, even if I call cancel, but it doesn't. How can I wait for the future to finish?
        }
        break; //OK, everything is finished, exit the wait loop.
    } catch( InterruptedException e ) {
        wasInterrupted = true; //We'll rethrow the exception laster as an AbortException.
        //Need to wait for futures to finish, even if it's canceled.
        log.info( "Attempting to interrupt threads that are reading changes..." );
        for( Future<Void> future : futures ) {
            future.cancel( true ); //I want to tell the threads to 'hurry up' and skip non-essential stuff.
        }
    } catch( ExecutionException e ) {
        throw e.getCause();
    }
}

//I shouldn't get to this line until all futures have finished!
like image 888
Jesse Barnum Avatar asked Jan 11 '14 22:01

Jesse Barnum


People also ask

How do you end a Completable Future?

Overview. In Java, we use an instance method of the CompletableFuture class, cancel() , that attempts to cancel the execution of a task.

How to interrupt a thread in ExecutorService?

Another way to interrupt the executor's internally managed thread(s) is to call the shutdownNow(..) method on your ExecutorService . Note, however, that as opposed to @erickson's solution, this will result in the whole ThreadPoolExecutor becoming unfit for further use.

What is cancel Future?

Invoking cancel(true) will prevent the Future from executing if not already run and will be interrupted if currently running. At this point, the burden to cancel the Future is put on the developer.

Can a callable task be cancelled?

When we submit a task (Callable or its cousin Runnable) for execution to an Executor or ExecutorService (e.g. ThreadPoolExecutor), we get a Future back which wraps the tasks. It has a method called Future. cancel(...) which can be used to cancel the task the future wraps.


1 Answers

How to interrupt a Future, but still wait for it to finish?

Interesting problem. Your code won't work because when you cancel a Future, as you have discovered, you cannot call get() again on it because that will throw a CancellationException.

If I am understanding your requirements:

  • You need to be able to interrupt the threads because you want to stop sleep, wait, etc..
  • You still want to be able to get the results of the tasks after they have been canceled.

On thing to do is to not use Futures here. To instead use your own job wrappers and to wait for the ExecutorService itself to finish with executorService.awaitTermination(...).

If you need the result of your tasks then your Runnable wrapper class would hold the result of the calculation and would have a boolean done flag. The waiting thread would wait for each Runnable for their done flag to be set to true. When the wrapper finishes its run() method, it would set done and notify() on itself. It would need to do that in a finally block.

If the waiting thread is interrupted, it would call executorService.shutdownNow(true) to interrupt all of the threads but would continue to loop waiting for them to finish.

Something like that.

like image 190
Gray Avatar answered Sep 17 '22 21:09

Gray