I want to be able to cancel a method marked with the #Async annotation by it's future.
I have a Spring method marked with the #Async annotation. This method does some computation, and eventually returns a result. All examples I have seen recommend using the AsyncResult class to return this Future.
#Async
public Future<String> run() {
// ... Computation. Minutes pass ...
return new AsyncResult<String>("Result");
}
I call the following method, from another Component, in the following manner. For example purposes, I wish to immediately cancel this thread:
Future<String> future = component.run();
future.cancel(true);
In this case, the thread will never be cancelled. This is because, looking at the Spring implementation for AsyncResult here: https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java#L71 , this method doesn't actually do a single thing. It simply returns false, that the thread could not be cancelled. This is my problem. How can I cancel the Thread being created by the #Async method? I have no access to the internal thread being created by Spring - so I have no means myself with which to cancel it, do I?
Actually, Spring #Async uses a background thread pool of it's own. And as long as cancel() method of Future or shutdownNow() of executor service is concerned, Calling executor.shutdownNow() or future.cancel(true) don’t stop the ongoing thread immediately. What these methods do is simply call .interrupt() on the respective thread(s). And interrupts has no guaranteed immediate effect. It issues a flag so whenever in sleeping or waiting state, the thread will be stopped.
To be noted, If your tasks ignore the interruption, executor.shutdownNow() and future.cancel(true) will behave exactly the same way as executor.shutdown() and future.cancel(false).
If you need a way to stop the slow or blocking operation. If you have a long/endless loop, you can just add a condition whether Thread.currentThread().isInterrupted() and don’t continue if it is true(end the operation).
Related
This question is Related to List returned from shutdownNow() can not be converted to submitted Runnable
Problem definition
I want to get runtime exception from Runnableand which I can get only using submit() call which returns me Future<?>.
If I use Submit I loose on the functionality which is provided by execute. As I will no longer able to use shutdownNow() to track not started threads.
So Is this true
If I want to catch runnable exception from my task I will never be able to use shutdownnow to find out not started task.
You can use execute() together with Future by using a custom subclass of FutureTask (which is a Runnable). for most Executors, calling submit() just wraps the Runnable/Callable with a FutureTask under the hood. In you custom subclass of FutureTask, keep a reference to the underlying Runnable/Callable and expose a method for returning it. then, when you call shutdownNow(), the returned Runnables should be instances of your custom FutureTask. (it's annoyting that you need to subclass FutureTask to be able to get at the underlying task, but that's the way it is).
I am using ScheduledExecutorService, and after I call it's cancel method on scheduleFuture, I can't schedule a Runnable on it. Calling scheduleAtFixedRate(runnable, INITIAL_DELAY, INTERVAL, TimeUnit.SECONDS) after cancel(), nothing happens. Is there any way to restart the ScheduledExecutorService after cancel() method is called?
Please review notes on Future and its implementation FutureTask.
The effect of calling cancel() method is that:
subsequent calls to isDone() will always return true. Subsequent
calls to isCancelled() will always return true if this method
returned true.
Once the computation has completed, the computation cannot be
restarted or cancelled.
Meaning, if a call to isDone() returns true, whether or not you made a call to cancel(), you can't use same instance of your service.
If I submit some tasks to an Executor using invokeAll, am I guaranteed that the submitted thread sees all the side effects of the task executions, even if I don't call get() on each of the returned Futures?
From a practical point of view, it would seem that this would be a useful guarantee, but I don't see anything in the javadoc.
More precisely, do all actions in the body of a Callable submitted to an executor happen-before the return from the invokeAll() call?
It's annoying to uselessly call get() on each future, when in fact the return type is Void and no exceptions are thrown - all the work in the happens as side-effects.
From the documentation of ExecutorService:
Actions in a thread prior to the submission of a Runnable or Callable
task to an ExecutorService happen-before any actions taken by that
task, which in turn happen-before the result is retrieved via
Future.get().
As I read this, there is a memory barrier on task submission, so potentially you'd need to call get() on the last task in your list to, but not the others.
However, since calling get() is the only way to determine whether the task completed or threw, I would still call it on every Future, regardless of memory guarantees.
If invokeAny() promises that no tasks are still in execution when invokeAny() returns, this will be the case: all side effects are visible.
In order for invokeAny() to know that all tasks are done, it needs to have synchronized with those threads, meaning that the returning of the functions happens after the tasks completing (and everything that happens in the task). However the API of 'ExecutorSerive' and 'Future.cancel()' does not explicitly say what happens when you cancel a running task (in particular: will cancel() wait with returning until the tasks has stopped running. The fact that after calling cancel(), isDone() must return true, does imply that cancel() will not return until the task has actually finished executing.
One more thing to watch out for is that you will not know if a task ever started execution, when using invokeAny() without inspecting the Future objects.
In my Callable code I use signaling to notify multiple ending behaviours to another thread. The Callable objects are queued up with FutureTasks in an Executor. They may also be cancelled after being queued up.
Now, my problem is that I rely on the tasks atleast being started for my signaling to work, but it looks like the Executor just skips a task if it's been marked as canceled before it got a chance to run it.
So, is there a way to garantee that a task is always started, and always cancelled (by InterruptedException) while running.
Also, can you check if a task has not started but failed?
You can probably subclass FutureTask class and override its done() method to perform the signalling. According to the documentation, this method should be called even if the task has been cancelled.
I am currently hunting a nasty bug in a multi-threaded environment using FutureTasks and Executors. The basic idea is this to have a fixed number of threads execute individual FutureTasks that compute a result that is to be displayed in a a table (never mind the GUI aspect here).
I have been looking at this for so long, I am beginning to doubt my sanity.
Consider this piece of code:
public class MyTask extends FutureTask<Result> {
private String cellId;
...
protected void done() {
if (isCancelled()) return;
try {
Result r = get(); // should not wait, because we are done
... // some processing with r
sendMessage(cellId, r);
} catch (ExecutionException e) { // thrown from get
...
} catch (InterruptedException e) { // thrown from get
...
}
}
...
}
When done() is called by an Executor handling an instance of MyTask, I check if I got there, because the task was cancelled. If so, I skip all remaining activities, especially I do not call sendMessage().
The documentation for FutureTask.done() says:
Protected method invoked when this task transitions to state isDone (whether normally or via cancellation). The default implementation does nothing. Subclasses may override this method to invoke completion callbacks or perform bookkeeping. Note that you can query status inside the implementation of this method to determine whether this task has been cancelled.
(API Reference)
But what I do not get from the documentation of FutureTask are the semantics while done() is being executed. What if I pass the isCancelled() check at the beginning, but right after that some other thread calls my cancel() method? Will that cause my task to change its mind and reply isCancelled() == true from then on?
If so, how would I later know if the the message was sent? Looking at isDone() would just tell me that execution of the task was finished, but as isCancelled() were true then as well, I could not know if it got to send the message out in time.
Maybe this is obvious, but I do not really see it right now.
FutureTask#done() is called no more than once for any given instance, and it's only called for one reason -- run() completed either with or without error, or cancel() ran before either of the preceding events occurred. The record of completion by any of these outcomes is latching. The reason a FutureTask completed can't change, regardless of competing events seemingly happening "at the same time."
Hence, within FutureTask#done() only one of isCancelled() or isDone() will return true then and forever more. It's difficult to distinguish between isDone() reporting true by way of error or successful completion. You can't override set() or setException(Throwable) decisively, as both delegate to the inner AQS to decide whether the attempt to record a successful yielding of a value or encountering an exception should stick. Overriding either method only lets you know that it was called, but you can't observe the decision made by the base implementation. If either event occurs "too late"—say, after cancellation—the attempt to record the value or the exception will be ignored.
Studying the implementation, the only way I see to discern a non-canceled successful outcome from an error is to bite the bullet and call get().
From the API (emphasis mine):
public boolean cancel(boolean mayInterruptIfRunning)
Description copied from interface: Future
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason.
So FutureTask is working off the assumption that you cannot cancel a task when it has transitioned to the isDone stage.
Why not send the message "outside" of the task, based on the outcome of the Future<V> object returned by an ExecutorService? I've used this pattern and it seems to work well: Submit a bunch of Callable<V> tasks through an ExecutorService. Then, for each primary task, submit a secondary task that waits on the Future<V> of the primary task and does some follow-up action (like send a message) only if the Future<V> indicates that the primary task completed successfully. There is no guesswork with this approach. When the call to Future<V>.get() returns, you're guaranteed that the task has reached a terminal state, as long as you don't call the version of get that takes a timeout argument.
If you take this approach, you should use two separate ExecutorService instances: one for the primary tasks and one for the secondary ones. This is to prevent deadlocks. You don't want secondary tasks to start up and potentially block primary tasks from starting when the thread pool size is limited.
There's no need to extend FutureTask<V> at all. Just implement your tasks as Callable<V> objects. But if for some reason you want to detect if the task was canceled from within the Callable<V> code, just check the interrupt status of the thread with Thread.interrupted().
I suggest to write a small test case which allows you to call cancel() while your Future instance hangs in done() and see what happens.