Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In which thread FutureCallback will be called for a ListenableFuture in Guava?

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.

like image 447
Kai Avatar asked Jan 28 '26 02:01

Kai


1 Answers

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 addCallback on the same thread where addCallback was 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();
     }
   }
like image 167
Louis Wasserman Avatar answered Jan 30 '26 14:01

Louis Wasserman