Is nesting of futures an anti pattern? - java

I have a ListenableFuture that I am creating like:
ListenableFuture<X> future1 = ...
ListenableFuture<X> future2 = ...
Futures.addCallback(future1, futureCallback, executor);
Now inside the futureCallback I do :
public void onSuccess(Object result) {
Object f2 = future2.get();
.
.
. <do something with f2>
}
Is it a bad thing to do a .get() call in a callback? I was told that I could get into a hung up state. Is that true and why would it so happen?
What is the alternative of achieving the same thing in a better way?

You probably want something more like:
whenAllSucceed(future1, future2).run(...)
The Runnable you pass to run will still have to call future2.get. Still, whenAllComplete has some advantages over the addCallback approach:
The addCallback approach may require a thread to block on future2.get until future2 is done. (This is at least a small waste of resources. If you run out of threads, your code may hang. Or you might try to create a new thread and run out of memory.) With whenAllComplete, your Runnable won't run until both input futures are done, so future2.get will not block.
whenAllComplete returns a Future. You can use this to check for errors. And if you cancel it, it will cancel both input futures.
Note also that whenAllSucceed will log if multiple inputs fail. This isn't always desirable. If you don't want the logging, you might prefer whenAllComplete. (Hopefully someday we will provide a way to turn off the logging.)

Doing a .get() call in a callback is outright usual -- it's what you want to do most of the time -- but a more standard pattern is to, instead, use transform or transformAsync to pass in a function that takes the result directly.

Doing blocking operation in callback (e.g. future.get) destroys the idea of asynchronous programming, turning asynchronous program in ordinary multithreaded. So this is indeed an antipattern.
It's OK, however, to call get() if you are sure it would not block.
If you want a callback which waits for 2 asynchronous results, you can use CompletableFuture instead:
CompletableFuture<X> future1 = ...
CompletableFuture<X> future2 = ...
CompletableFuture future3 = future1.thenCombineAsync(future 2, futureCallback, executor);

Related

Will a chain of method calls (CompletableFuture API) execute asynchronously if the first method in a chain is asynchronous?

I'm studying CompletableFuture API and there is an example:
CompletableFuture.completedFuture(url)
.thenComposeAsync(this::readPage, executor)
.thenApply(this::getImageURLs)
.thenApply(this::saveFoundImages)
.....
I have a question: if I call the thenComposeAsync(...) method as the first one, will the other methods in the chain execute in the executor which I passed through the params, or I should call the other methods using async to get asynchronous execution in a particular executor?
OK, so there are 3 types of methods in CompletableFuture. For example:
thenApply()
thenApplyAsync(Function) (without an Executor)
thenApplyAsync(Function, Executor) (with an Executor)
The last one means that this action will execute in the Executor that you pass to it and it is the most obvious one.
The second one means that the action is executed in the ForkJoinPool.
The first one is far more interesting. The documentation makes it sound like it's easy, via:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method
And you need to start bisecting this into smaller pieces. What you need to understand that there are threads that complete a certain CompletableFuture, there are threads that execute some actions on it and there are threads that chain certain dependent actions. Potentially, these are all different threads. And this is where it all begins:
If the dependent action is already chained, the thread that will call complete is going to be the thread that executes this action.
If the future is already completed, then the thread that chains the action will execute it.
Since there is no linear actions on the steps above, it is literally impossible to say for sure in which thread your thenApply will execute, at least with 100% certainty. That action can be executed in any of :
the thread that calls complete/completeExceptionally
the thread that does the chaining of thenApply
the thread that calls join/get
Any of the above is a possibility. If you really want I made a rather interesting test here, proving some of the things above.
I am not trying to pick on the other answer, but he made a rather interesting point that I was very confused about in the begging too:
In your example: After .thenComposeAsync also all the following chained futures will get completed by executor.
We can easily prove that this is not correct:
CompletableFuture<String> future1 = CompletableFuture.completedFuture("a");
CompletableFuture<String> future2 = future1.thenApplyAsync(x -> "b" + x, Executors.newCachedThreadPool());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
CompletableFuture<String> future3 = future2.thenApply(x -> {
System.out.println(Thread.currentThread().getName());
return x + "c";
});
future3.join();
What you are going to see if you run this, is that main actually executes thenApply, not a thread from the pool.

Java CompletableFuture get Method

I am having some trouble understanding CompletableFuture. I do not understand the get() method. Please correct me if I am wrong, but it says
"Waits if necessary for this future to complete, and then returns its result." So If I do not return any result I do not have to call get method?
Please see below. Even I do not call get() method it still does its job. So I understand get() as if the future returns something it will make sense then, otherwise get() is not necessary for a future that does not return anything.
//Since it does not return something two statements below do the same thing.
CompletableFuture.runAsync(doSomething());
CompletableFuture.runAsync(doSomething()).get();
private final CompletableFuture<Void> doSomething() {
//do something
return null;
}
The main purpose of get() is to wait for the task to complete, then return the result.
If your task is a Runnable, not Callable, it will return a Void, so as you have pointed out, there is no point in checking the result. For such tasks you are executing get() only to wait for them to complete.
The main advantages of CompletableFuture are the methods that allow you to handle exceptions, and further process the data. It also has methods wo wait for all and single task to complete from a set of ComplatableFuture tasks. So it's mutch easyer to work in multithread anv. get() method works same as for Future class though.
UPDATE:
If you don't require for them to complete before passing further in your application, you don't have to call get() method at all. But it would be wise to keep a reference to them, and wait for them to complete or cancel them before exiting a program. At some point of the program you probably will want to see if they have completed.
But if you want for the to complete before going further, then you can use CompletableFuture.allOf().
In some cases it's also wise to add a timeout to their execution, so that you will not have a hanging thread in your application. This may be dangerous, especially on mobile environment.
So it all depends on your business case.

Recursively cancel an allOf CompletableFuture

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

Which executor is used when composing Java CompletableFutures?

I have a method on some repository class that returns a CompletableFuture. The code that completes these futures uses a third party library which blocks. I intend to have a separate bounded Executor which this repository class will use to make these blocking calls.
Here is an example:
public class PersonRepository {
private Executor executor = ...
public CompletableFuture<Void> create(Person person) {...}
public CompletableFuture<Boolean> delete(Person person) {...}
}
The rest of my application will compose these futures and do some other things with the results. When these other functions that are supplied to thenAccept, thenCompose, whenComplete, etc, I don't want them to run on the Executor for the repository.
Another example:
public CompletableFuture<?> replacePerson(Person person) {
final PersonRepository repo = getPersonRepository();
return repo.delete(person)
.thenAccept(existed -> {
if (existed) System.out.println("Person deleted"));
else System.out.println("Person did not exist"));
})
.thenCompose(unused -> {
System.out.println("Creating person");
return repo.create(person);
})
.whenComplete((unused, ex) -> {
if (ex != null) System.out.println("Creating person");
repo.close();
});
}
The JavaDoc states:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.
Side question: Why is there an or here? In what case is there another caller of a completion method that does not complete the current future?
Main question: If I want all the println to be executed by a different Executor than the one used by the repository, which methods do I need to make async and provide the executor manually?
Obviously the thenAccept needs to be changed to thenAcceptAsync but I'm not sure about that point onwards.
Alternative question: Which thread completes the returned future from thenCompose?
My guess is that it will be whatever thread completes the future returned from the function argument. In other words I would need to also change whenComplete to whenCompleteAsync.
Perhaps I am over complicating things but this feels like it could get quite tricky. I need to pay a lot of attention to where all these futures come from. Also from a design point of view, if I return a future, how do I prevent callers from using my executor? It feels like it breaks encapsulation. I know that all the transformation functions in Scala take an implicit ExecutionContext which seems to solve all these problems.
Side Question: If you assigned the intermediate CompletionStage to a variable and call a method on it, it would get executed on the same thread.
Main Question: Only the first one, so change thenAccept to thenAcceptAsync -- all the following ones will execute their steps on the thread that is used for the accept.
Alternative Question: the thread that completed the future from thenCompose is the same one as was used for the compose.
You should think of the CompletionStages as steps, that are executed in rapid succession on the same thread (by just applying the functions in order), unless you specifically want the step to be executed on a different thread, using async. All next steps are done on that new thread then.
In your current setup the steps would be executed like this:
Thread-1: delete, accept, compose, complete
With the first accept async, it becomes:
Thread-1: delete
Thread-2: accept, compose, complete
As for your last question, about the same thread being used by your callers if they add additional steps -- I don't think there is much you can do about aside from not returning a CompletableFuture, but a normal Future.
Just from my empirical observations while playing around with it, the thread that executes these non-async methods will depend on which happens first, thenCompose itself or the task behind the Future.
If thenCompose completes first (which, in your case, is almost certain), then the method will run on the same thread that is executing the Future task.
If the task behind your Future completes first, then the method will run immediately on the calling thread (i.e. no executor at all).

Non-cancellable futures returned by a thread-pool. Do they exist?

I'm currently implementing a service that works in a concurrent setting and that has as operations a bunch of blocking methods.
I would like to change that so they return a Future<?> instead and it's up to the client to decide whether he wants to execute get() and block the thread or not. The problem is that Future<?> brings baggage, ie, it is possible to invoke cancellation on a future. But if that were to actually happen then it would most probably break my service's invariants.
Is there any easy way to make a thread-pool return non-cancellable futures? Currently, the only solution I'm seeing is wrapping the thread-pool future's into a future of mine that will throw an UnsupportedException if some attempts to cancel the operation. Or just return an object of my own, but I'd like to KISS if possible.
I think, you fear too much. I see two VERY simple solutions:
decorate (wrap) the default FutureTask and override in your ExecutorService the newTaskFor() method returning your new class.
do nothing, i.e do not cancel any work in your Callables or Runnables. In order to make your life easier you could take a look at Guava's uninterruptibles.

Categories

Resources