fish748
fish748

Reputation: 183

Are FutureCallbacks added to the ListenableFuture executed asynchronously?

In the code below, I added 2 FutureCallbacks to a single ListenableFuture.

And my question is: will the 2 FutureCallbacks be executed by the order I add them, or will they run separately and asynchronously?

The JavaDoc said, Registers separate success and failure callbacks to be run when the Future's computation is complete or, if the computation is already complete, immediately. There is no guaranteed ordering of execution of callbacks, but any callback added through this method is guaranteed to be called once the computation is complete.

I tried to add Thread.sleep(1000) to one of the FutureCallbacks, then I found it blocks the other one, which confused me.

And I've also tried the addListener method, it runs asynchronously, that's for sure.

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
final ListenableFuture<String> future = service.submit(new Callable<String>() {
  @Override
  public String call() throws Exception {
    return "hello";
  }
});

Futures.addCallback(future, new FutureCallback<String>() {
  @Override
  public void onSuccess(String result) {
    System.out.println(result+ " world");
  }

  @Override
  public void onFailure(Throwable t) {
  }
});

Futures.addCallback(future, new FutureCallback<String>() {
  @Override
  public void onSuccess(String result) {
    System.out.println(result+ " me");
  }

  @Override
  public void onFailure(Throwable t) {
  }
});

Upvotes: 0

Views: 3557

Answers (1)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279960

will the 2 FutureCallbacks be executed by the order I add them, or will they run separately and asynchronously

First, it's important to note that Callback instances and listeners registered after a Future has completed trigger immediately.

The javadoc states

Note: If the callback is slow or heavyweight, consider supplying an executor. If you do not supply an executor, addCallback will use a direct executor, which carries some caveats for heavier operations. For example, the callback may run on an unpredictable or undesirable thread:

  • If the input Future is done at the time addCallback is called, addCallback will execute the callback inline.
  • If the input Future is not yet done, addCallback will schedule the callback to be run by the thread that completes the input Future, which may be an internal system thread such as an RPC network thread.

Also note that, regardless of which thread executes the callback, all other registered but unexecuted listeners are prevented from running during its execution, even if those listeners are to run in other executors.

You can control if they are run separately by providing separate Executors when adding them (or the same but pooled). If you don't, the behavior is unpredictable, as the javadoc states.

(This is from a more recent version of Guava, but I think it applies to older versions as well.)

Upvotes: 1

Related Questions