Reputation: 573
when going through the ListenableFutre interface, it notes in the doc that
addListener()
Registers a listener to be run on the given executor. The listener will run when the
Future
's computation is complete or, if the computation is already complete, immediately.`
Since Future.get()
is a blocking call, how does Java guarantee certain future is Done? are they spinning on this? I understand that with Framework like dagger producers, it is kinda easy to understand (once task is done, write to something, the monitoring thread will be notified). in ListenableFuture case, does jvm support something like this out of box?
using wait()/notify()
like mechanism ?
FollowUp Question: as all of you put, it is the caller actually guarantee the listener to be run, normal case to use a ListenableFuture
would be ListenableFuture future = Caller.call()
, with caller and callee in different threads or even in different JVMs, how is this done in java? the listener in stored in both the caller thread and callee thread ? or using remote reigstery when in differnt JVMs?
Upvotes: 1
Views: 3821
Reputation: 8481
As already mentioned, the best way to understand the ListenableFuture
is to look how it is implemented. When you call addListener(Runnable listener, Executor exec)
, you provide a Runnable
listener and an Executor
to run this listener, so it is you who decides how your listener is executed.
the listener is stored in both the caller thread and callee thread ?
The listener is stored inside the future, in the ExecutionList
:
// The execution list to hold our executors.
private final ExecutionList executionList = new ExecutionList();
And addListener(Runnable listener, Executor exec)
does just following:
public void addListener(Runnable listener, Executor exec) {
executionList.add(listener, exec);
}
So when the future completes, it calls the set(V value)
method:
protected boolean set(@Nullable V value) {
boolean result = sync.set(value);
if (result) {
executionList.execute();
}
return result;
}
and all listeners are executed like this: executor.execute(runnable);
Upvotes: 1
Reputation: 2776
I'd like to add answers.
Guava does not garantee it. If you down JVM or JVM is crashed no listeners would be invoked. If you shutdown executor without cancelling futures, no listeners would be invoked too. I mean this case:
ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(false);
return t;
}
});
ListenableFuture<?> listenableFuture = JdkFutureAdapters.listenInPoolThread(
executorService.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run!!!");
}
}),
executorService
);
Futures.addCallback(listenableFuture, new FutureCallback<Object>() {
@Override
public void onSuccess(@Nullable Object result) {
System.out.println("onSuccess");
}
@Override
public void onFailure(Throwable t) {
System.out.println("onFailure");
}
});
MoreExecutors.shutdownAndAwaitTermination(executorService, 3, TimeUnit.SECONDS);
I didn't see "onSuccess" or "onFailure", did you?
In usual workflow when JVM is running, Guava uses CAS to invoke listeners exactly once, you can see it in source code too.
Upvotes: 0
Reputation: 48824
There's nothing magic going on with ListenableFuture
- the contract of the interface simply requires that any implementations invoke any registered listeners upon completion (or immediately, if already done).
It may help to look at one such implementation, AbstractFuture
- specifically look at the .complete()
method, which is invoked immediately after the future becomes "done" (by finishing, failing, or being cancelled). In order to be both fast and thread-safe the details are somewhat complex, but essentially that's all it does.
Upvotes: 2