Reputation: 2325
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?
Upvotes: 1
Views: 813
Reputation: 13535
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);
Upvotes: 0
Reputation: 4002
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.)
Upvotes: 1
Reputation: 198481
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.
Upvotes: 0