Is a Future task considered finished, isDone()==true when it hits the return statement?
For example:
ExecutorService executor = newSingleThreadExecutor();
Future<> result = executor.submit(new Runnable()
{
#Override
public void run()
{
return;
}
}
Is result considered done when it hits the return ?
More or less. The javadoc is ambiguous for what it exactly means but generally, when the callable returns, very shortly after isDone() will be true (or if an exception occurs the same is true).
Completion of Future.get is considered to pin point a Future's completion.
To quote from java docs
A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. Cancellation is performed by the cancel method. Additional methods are provided to determine if the task...
In other words till the time Future doesn't complete the call to Future.get will be blocked and hence completion of Future.get should be considered as completion of Future (normal or exceptional)
P.S.: Future.isDone should only be used to check the status and no way an indication as when the Future was completed.
Related
My code is as follows:
public Future<String> getFuture() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(() -> {
//do something
return "test string";
});
executorService.shutDown(); // is this correct?
return future;
}
I am calling this service from other class to get the future:
Future<String> future = getFuture();
String result = future.get();
future.cancel(true); // will this assure that there wont be any thread leak?
Now out of executorService.shutDown() and future.cancel(true) which will assure that there wont be thread leaks?
Note that after calling future.cancel(true) when I check currently running threads in the result of Thread.getAllStackTraces() I can still find the thread where future executed.
You are asking the wrong question!
There is no point in creating a service within a method to then throw it away right there.
Creating that service instance doesn't come for free. The whole idea of this abstraction is to ensure to make efficient usage of infrastructure elements!
In other words: step back and rework your design; so that this service becomes a field of some class for example! And yes, that might turn out to be complicated. But most likely, spending time in that corner will pay out much more long term - compared to continuing the approach shown in your question.
It is a bad idea to create an executor then throw it away in each method call.
Now out of executorService.shutDown() and future.cancel(true) which will assure that there wont be thread leaks?
none of them.
executorService.shutdown() will just keep running the current tasks and reject new submitted tasks.
future.cancel(true) will interrupt the corresponding task if it is currently running (but it is your responsability to check if the task was interrupted and finish the execution of the task as soon as possible)
Note that after calling future.cancel(true) when I check currently running threads in the result of Thread.getAllStackTraces() I can still find the thread where future executed.
as I mentioned before, future.cancel(true) doesn't stop the thread. it only sends an interruption.
If I have
CompletableFuture<Something> future1 = service.request(param1);
CompletableFuture<Something> future2 = service.request(param2);
CompletableFuture<Void> many = CompletableFuture.allOf(future1, future2);
what will happen when I do many.cancel()? Will future1 and future2 be cancelled as well? If not, what would be the cleanest way to achieve this? I'm reluctant to hold on to future1 and future2, just to be able to cancel them when I want to cancel many.
Some background on why I want this: when receiving a piece of data, I need to request matching, potentially future data to perform a computation. If a newer piece of data arrives, I want to cancel the completion of the earlier computation, because the result will immediately be superceded by the new computation.
Before you make you life harder than necessary, you should become aware of what cancelling a CompletableFuture actually does. Most important, it does not stop the associated computation.
If a computation associated with a CompletableFuture is already running, but has not completed yet, cancelling a CompletableFuture turns it into the “cancelled” state, which may have an immediate effect on all dependent stages, but not on the computation, which will continue until complete, though its attempt to complete the cancelled future will not have any effect.
While other Future’s might be cancelled with interruption, which will stop the computation, if it checks for interruption, this doesn’t apply to CompletableFuture, see CompletableFuture.cancel(boolean):
Parameters:
mayInterruptIfRunning - this value has no effect in this implementation because interrupts are not used to control processing.
So when you cancel either, future1 or future2, successfully, the only immediate effect would be the cancellation of many, which you can also achieve by calling cancel on many itself. It would have a broader effect, if there were more dependent stages, but since you stated, that you don’t want to keep references to future1 or future2, this doesn’t seem to be the case.
The following code demonstrates the behavior:
CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
System.out.println("supplying value");
return "foo";
});
CompletableFuture<String> then = supply.thenApply(s -> {
System.out.println("Evaluating next stage");
return s;
});
CompletableFuture<?> last = then.handle((s,t) -> {
System.out.println("last stage: value: "+s+", throwable: "+t);
return "";
});
System.out.println("cancelling: "+supply.cancel(true));
ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);
This code reproducible prints:
last stage: value: null, throwable: java.util.concurrent.CompletionException: java.util.concurrent.CancellationException
canceling: true
supplying value
(the order might change)
regardless of whether you call supply.cancel(true) or then.cancel(true) or whether you pass true or false; it won’t stop the ongoing Supplier evaluation.
There will be a difference, if the associated computation hasn’t been started yet and it does check the cancellation state when starting, like with the actions produced by the convenience methods in CompletableFuture. This is a rare situation, as normally, your service.request(paramN) call is supposed to trigger the evaluation.
It’s a fundamental property of the CompletableFuture, as its name suggests, that it is completable, i.e. anyone could call complete on it, thus, the CompletableFuture can’t control whoever might eventually call complete on it in the future. So all, cancel can achieve, is to set it to the cancelled state, which implies ignoring subsequent completion attempts and propagating the cancellation downward to the dependent actions.
So the bottom line is that you might already be fine with just calling cancel on the many instance, because calling cancel on future1 and future2 is unlikely to have an effect that is worth the complication of your code.
The tree constructed by CompletableFuture.allOf doesn't hold any references to the given instances of CompletableFuture. Instead if just builds completion tree, which is is completed when all of the given CompletableFutures complete (from JavaDocs).
So probably you have to keep references to all CompletableFuture in order to cancel them sequentially when it is needed.
You can give a try for my library: https://github.com/vsilaev/tascalate-concurrent
It provides both truly cancelable CompletionStage implementations (CompletableTask) as well as methods to combine them (Promises.all)
CompletionStage<Something> future1 = CompletableTask
.complete(param1, myExecutor).thenApplyAsync(this::serviceCall);
CompletionStage<Something> future2 = CompletableTask
.complete(param2, myExecutor).thenApplyAsync(this::serviceCall);
Promise<List<Something>> many = Promises.all(future1, future2);
Now you can call many.cancel(true) and both future1 and future2 will be cancelled (if not yet completed). Moreover, if either of individual futures completes exceptionally, then another one will be cancelled automatically (again, if not yet completed).
If I have the following code, which works fine:
ExecutorService service = Executors.newFixedThreadPool(100);
[....]
List<Future<SomeObject>> futures = service.invokeAll(callables);
for (Future f : futures) {
f.get();
}
// shutdown the service after all Callables are finished.
service.shutdown();
boolean serviceIsShutDown = service.awaitTermination(5, TimeUnit.SECONDS);
if (serviceIsShutDown) {
System.out.println("Service terminated normally. All ok.");
} else {
// What if it's not shutDown?
[...]
// this?
//service = null;
}
Question: What if the call
boolean serviceIsShutDown = service.awaitTermination(5, TimeUnit.SECONDS);
returns false because the timeout hits?
I guess the Threads in the ExecutorService will remain in state WAIT. What is the best solution to continue?
Setting the service to null and having the GarbageCollector remove it? But what happens with the related Threads? Will it ever be garbage collected as there are still references?
The code usually works, but just be curious. What to do if it returns false?
If awaitTermination() returns false in your example, you have an option to try calling shutdownNow(). This method will do its best to cancel all the tasks that are still being executed, but it guarantees nothing. Some poorly implemented tasks might have no cancellation policy and just run forever. In this case, the threads will never be terminated and the executor will never be garbage collected.
Such tasks will also prevent your program from graceful termination (if you don't mark your working threads as daemons).
For instance, if your task only contains an empty infinite loop, it won't be cancelled even if you call shutdownNow().
There also might be the case that a task has no proper cancellation policy, and runs too long (but not forever). For instance, it has a very-very long empty loop. You might fail to shutdown a pool that is being executed such task by means of shutdown()/shutdownNow(), but sooner or later it will finish its work and the thread will be terminated along with the executor.
If you want to "force" the termination of your ExecutorService just use:
shutdownNow()
look here for description:
I have created ExecutorService like:
private static final java.util.concurrent.ExecutorService EXECUTOR_SERVICE = new java.util.concurrent.ThreadPoolExecutor(
10, // core thread pool size
5, // maximum thread pool size
1, // time to wait before resizing pool
java.util.concurrent.TimeUnit.MINUTES,
new java.util.concurrent.ArrayBlockingQueue<Runnable>(MAX_THREADS, true),
new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
and added threads in to it with below code:
EXECUTOR_SERVICE.submit(thread);
Now I want know when all threads in EXECUTOR_SERVICE have finished their task so that I can do some dependent tasks.
Kindly suggest any way to achieve it.
You could use :
try {
executor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// Report the interruptedException
}
Use CountDownLatch. I have used this before in the past with great success.
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
The Javadoc link has a great example.
As per Java Doc Signature of submit Method is <T> Future<T> submit(Callable<T> task)
and Submits a value-returning task for execution and returns a Future representing the pending results of the task. The Future's get method will return the task's result upon successful completion.
If you would like to immediately block waiting for a task, you can use constructions of the form result = exec.submit(aCallable).get();
Note: The Executors class includes a set of methods that can convert some other common closure-like objects, for example, PrivilegedAction to Callable form so they can be submitted.
which return
Future representing pending completion of the task
Without modifying your submitted tasks, you are left to either query the internal state of ThreadPoolExecutor, subclass ThreadPoolExecutor to track task completion according to your requirements, or collect all of the returned Futures from task submission and wait on them each in turn until they are all done.
In no particular order:
Option 1: Query the state of ThreadPoolExecutor:
You can use ThreadPoolExecutor.getActiveCount() if you keep your reference typed to ThreadPoolExecutor instead of ExecutorService.
From ThreadPoolExecutor source:
/**
* Returns the approximate number of threads that are actively executing tasks.
* Returns:
* the number of threads
**/
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
The JavaDoc there that mentions "approximate" should concern you, however, since given concurrent execution it is not necessarily guaranteed to be accurate. Looking at the code though, it does lock and assuming it is not queried in another thread before all of your tasks have been added, it appears to be sufficient to test for task completeness.
A drawback here is that you are left to monitor the value continuously in a check / sleep loop.
Option 2: Subclass ThreadPoolExecutor:
Another solution (or perhaps a complementary solution) is to subclass ThreadPoolExecutor and override the afterExecute method in order to keep track of completed executions and take appropriate action. You could design your subclass such that it will call a callback once X tasks have been completed, or the number of remaining tasks drops to 0 (some concurrency concerns there since this could trigger before all tasks have been added) etc.
Option 3: Collect task Futures (probably the best option):
Each submission to the ExecutorService returns a Future which can be collected in a list. A loop could then run through and wait on each future in turn until all tasks are complete.
E.g.
List<Future> futures = new ArrayList<Future>();
futures.add(executorService.submit(myTask1));
futures.add(executorService.submit(myTask2));
for (Future future : futures) {
// TODO time limit, exception handling, etc etc.
future.get();
}
Long story short: I have a collection of Future objects. Some of them are already in progress, some are not. I iterate the collection and call future.cancel(false) which, according to the documentation, should cancel all Futures that are not currently running but should allow all the others to complete.
My question is: How do I know when a particular Future is completed after I have called future.cancel(false)? future.isDone() always returns true because cancel() was indeed called before that and future.get() always throws a CancellationException even though the Future is still running.
Any suggestions?
Since Future models the future result of a pending computation, and since that result is not forthcoming from a canceled future, it is reasonable that Future gives you no way to find out when the computation whose result has been disposed of will complete. In other words, you'd need another paradigm to achieve your goal with that approach.
If your wish is to wait for all the submitted tasks to complete, the closest thing which is directly supported by the Executor Service API is to shut down the entire executor service and wait for its termination.
If the above does not fit your solution, then I don't see a better approach than some custom solution, for example a custom implementation of Runnable, which does some housekeeping on the side so you can check when it has completed running.
You could add a flag to your Future implementation which will reflect the actual Future' state
given a Callable<Object> c:
futureTask1 = new FutureTask<Object>(c);
futureTask2 = new FutureTask<Void>(futureTask1, null);
executor.execute(futureTask2);
now if you want the result:
futureTask1.get()
if you're no longer interested in the result:
futureTask1.cancel(mayInterruptIfRunning)
if you want to wait to be sure the code in the callable is not (and will not become) running (whether never called, finished cancelling or finished producing the result):
futureTask2.get()
Even if cancelled before it started working, this waits for the executor to execute the scheduled task (which will to nothing if already cancelled), so this may unnecessariliy wait for other long-running tasks to complete. YMMV