I must have missed something. I had a hard time to understand in which thread FutureCallback will be called for a ListenableFuture in Guava.
The first version of my code is:
Log.d("mydebug", "Before submit, " + Thread.currentThread() + ", " + android.os.Process.myTid());
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture future = service.submit(new Runnable() {
@Override
public void run() {
Log.d("mydebug", "In run, " + Thread.currentThread() + ", " + android.os.Process.myTid());
}
});
Futures.addCallback(future, new FutureCallback() {
@Override
public void onSuccess(Object result) {
Log.d("mydebug", "In onSuccess, " + Thread.currentThread() + ", " + android.os.Process.myTid());
}
@Override
public void onFailure(Throwable thrown) {
Log.d("mydebug", "In onFailure, " + Thread.currentThread() + ", " + android.os.Process.myTid());
}
}, MoreExecutors.sameThreadExecutor());
The output for the first version of my code is:
02-04 12:37:00.815 11327 11327 D mydebug : Before submit, Thread[main,5,main], 11327
02-04 12:37:00.825 11327 11382 D mydebug : In run, Thread[pool-1-thread-1,5,main], 11382
02-04 12:37:00.825 11327 11327 D mydebug : In onSuccess, Thread[main,5,main], 11327
I added Thread.sleep into the Runnable to make the second version of my code:
Log.d("mydebug", "Before submit, " + Thread.currentThread() + ", " + android.os.Process.myTid());
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture future = service.submit(new Runnable() {
@Override
public void run() {
Log.d("mydebug", "In run, " + Thread.currentThread() + ", " + android.os.Process.myTid());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Futures.addCallback(future, new FutureCallback() {
@Override
public void onSuccess(Object result) {
Log.d("mydebug", "In onSuccess, " + Thread.currentThread() + ", " + android.os.Process.myTid());
}
@Override
public void onFailure(Throwable thrown) {
Log.d("mydebug", "In onFailure, " + Thread.currentThread() + ", " + android.os.Process.myTid());
}
}, MoreExecutors.sameThreadExecutor());
The output for the second version of code is:
02-04 12:43:02.165 17180 17180 D mydebug : Before submit, Thread[main,5,main], 17180
02-04 12:43:02.205 17180 17229 D mydebug : In run, Thread[pool-1-thread-1,5,main], 17229
02-04 12:43:04.215 17180 17229 D mydebug : In onSuccess, Thread[pool-1-thread-1,5,main], 17229
So in the first version of my code, FutureCallback was executed in the thread that called service.submit, while the second version of my code executed FutureCallback in a thread in the thread pool. I am confused. What exactly does MoreExecutors.sameThreadExecutor() mean? It didn't work as I expected.
The documentation is pretty explicit here:
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 [note: this is equivalent to
sameThreadExecutor()which you passed in explicitly], 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. [that is, directly in the call to
addCallbackon the same thread whereaddCallbackwas called]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.
Note the the "direct executor" is the simplest possible implementation of an executor:
final class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With