figaro
figaro

Reputation: 2325

Is nesting of futures an anti pattern?

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

Answers (3)

Alexei Kaigorodov
Alexei Kaigorodov

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

Chris Povirk
Chris Povirk

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

Louis Wasserman
Louis Wasserman

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

Related Questions