how to start and stop the scheduledexecutorservice multiple times - java

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.

Related

Need for ExecutorService.awaitTermination() after shutdown()

As per Javadocs, shutdown() will wait for all submit tasks to be executed. I have two questions:
What does submitted task mean? Do the tasks have to be submitted specifically by ExecutorService.submit() method or it included tasks submitted by ExecutorService.execute() method also?
I have added a shutdown hook which calls ExecutorService.shutdown(). As per the docs, it should wait for all submit tasks to be executed. But it doesn't until I add a awaitTermination() call after the shutdown() call. Why doesn't it execute all tasks without awaitTermination() call?
What does submitted task mean? Do the tasks have to be submitted specifically by ExecutorService.submit() method or it included tasks submitted by ExecutorService.execute() method also?
A 'submitted' task in this sense is any Runnable or Callable that was passed to the ExecutorService. Although the wording of the javadoc is slightly confusing, it does not differentiate between execute() vs submit().
I have added a shutdown hook which calls ExecutorService.shutdown(). As per the docs, it should wait for all submit tasks to be executed. But it doesn't until I add a awaitTermination() call after the shutdown() call. Why doesn't it execute all tasks without awaitTermination() call?
The shutdown() operation is non-blocking (asynchronous) as are almost all of the methods on the ExecutorService API. The javadoc only states that calling shutdown() will initiate a shutdown sequence.
The key here is that the ExecutorService will try to wait for all tasks to complete, but if shutdown() is the last line of code before your main method terminates, System.exit() will be called after the end of your main method which will terminate the JVM and override the ExecutorService's attempt to wait for running tasks to complete. I would consider it undesireable for ExecutorService.shutdown() to always delay a System.exit(), and would prefer an opt-in approach to a blocking call (i.e. awaitTermination).

Spring Cancel #Async Task

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).

Reliability of returned value of Future method cancel(false)

Suppose I schedule a task with a ScheduledThreadPoolExecutor and get a Future back.
I later decide I want to cancel that Future, and rely on the returned value of the cancel to trigger some cleanup operation. I don't want the task to be interrupted if it's already running (so I pass false as argument).
Is the return of the cancel reliable? That is, is it impossible that, if cancel returned "true", the task is actually being run?
Looking at the code in the OpenJDK 8 it looks like there could be a race condition, whereby the "cancel" sets the state of the task to CANCELLED and returns true, but the runner can already have passed the "check" to start execution.
As far as I can see, the computation will be performed but the result not set (which is good). However, in my case, the "computation" has side effects so I want to know if I cancelled it for real or not.
The javadoc of cancel(boolean) states
Attempts to cancel execution of this task. This attempt will fail if
the task has already completed, has already been cancelled, or could
not be cancelled for some other reason.
If successful, and this task
has not started when cancel is called, this task should never run. If
the task has already started, then the mayInterruptIfRunning parameter
determines whether the thread executing this task should be
interrupted in an attempt to stop the task.
Emphasis mine. The call will return true under all conditions which aren't failures. It is therefore possible that the method returns true and your task is running.

Are all side-effects of executor tasks visible after invokeAll?

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.

Java 5: java.util.concurrent.FutureTask - Semantics of cancel() and done()

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.

Categories