JDK Future

需要主动调用Future.get()

  1. public static void testFutureUse() throws ExecutionException, InterruptedException {
  2. ExecutorService executor = Executors.newFixedThreadPool(2);
  3. Future<String> submit = executor.submit(new Callable<String>() {
  4. @Override
  5. public String call() throws Exception {
  6. Thread.sleep(3000);
  7. System.out.println("begin do business");
  8. return "foo";
  9. }
  10. });
  11. System.out.println("submit finished");
  12. System.out.println(submit.get());
  13. System.out.println("result returned");
  14. }

Guava Future Callback

  1. public static void testCallbackUse() throws InterruptedException {
  2. ListeningExecutorService listeningExecutor =
  3. MoreExecutors.listeningDecorator(
  4. Executors.newFixedThreadPool(2, new ThreadFactoryBuilder()
  5. .setNameFormat("testCallbackUse-%d").build()));
  6. ListenableFuture<String> listenableFuture =
  7. listeningExecutor.submit(new Callable<String>() {
  8. @Override
  9. public String call() throws Exception {
  10. System.out.println("begin do business, owner=" + Thread.currentThread().getName());
  11. //Thread.sleep(3000);
  12. return "foo";
  13. }
  14. });
  15. System.out.println("submit finished");
  16. Futures.addCallback(listenableFuture, new FutureCallback<String>() {
  17. @Override
  18. public void onSuccess(String result) {
  19. System.out.println("result successfully returned, owner=" + Thread.currentThread().getName());
  20. }
  21. @Override
  22. public void onFailure(Throwable t) {
  23. System.out.println("result failed");
  24. }
  25. }, MoreExecutors.directExecutor());
  26. System.out.println("main await...");

Case1: Callable执行较快/基本无延迟

输出:

  1. submit finished
  2. begin do business, owner=testCallbackUse-0
  3. result successfully returned, owner=main
  4. main await...

可以看到,监听回调结果的执行线程是main线程

Case2: Callable执行耗时较长(如网络调用)

这里用Sleep来代替,输出:

  1. submit finished
  2. begin do business, owner=testCallbackUse-0
  3. main await...
  4. result successfully returned, owner=testCallbackUse-0

可以看到,监听回调结果的执行线程是执行Callable的线程池worker

解释

It Depends.

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.