首頁  >  問答  >  主體

异步编程 - 在Java中使用异步后,主方法如何返回异步中得到的值?

一个返回值为User的方法,在内部调用了异步方法(比如Rxjava,或者异步的网络请求),其内部匿名函数内才能拿到user对象,那么我的方法应该怎么return这个对象?

PHPzPHPz2717 天前463

全部回覆(7)我來回復

  • 天蓬老师

    天蓬老师2017-04-18 09:53:32

    方法的回傳值為user,那這個方法就不能叫非同步方法了。除非這個方法回傳future,或是類似可以在之後拿到結果的引用,這個方法才能叫異步方法。想調完方法後得到user,那麼方法裡面就沒有必要再放置非同步的程式碼了,一點意義都沒有。

    異步的回傳結果只能透過回調。

    同步的方法通常是這樣的

    public User syncGetUser() {
        User user = heavyWork();
        return user;
    }

    由於heavyWork方法可能需要查資料庫,或是做大量計算,所以heavyWork方法會執行大量的時間。
    如果你不想等待大量的時間,這時候非同步就可以派上用場了。

    public Future<User> asyncGetUser() {
        Future<User> future = threadPool.submit(new Callable<User> {
            public User call() throws Exception {
                return heavyWork();
            }
        }
        
        return future;
    }

    到了這裡,heavyWork已經交給另一個線程去跑了,並回到一個future給你。
    之後,你可以透過這個future的get方法得到你想要的user。

    這才是異步的意義和用處所在。題主的題目本身就是矛盾的。在一個含有非同步程式碼的方法裡面傳回非同步執行的結果,是一件矛盾的事情。

    回覆
    0
  • 阿神

    阿神2017-04-18 09:53:32

    我沒有研究過 RxJava,不過之前團隊裡面做 Android 的開發的同事說是很好用。

    1 樓給了一個使用 Future 的方案,但很抱歉 Future 是一種非同步阻塞式的API,也就是沒有通知回呼。

    至於回呼怎麼實現,這個應該很基本,去看看觀察者模式就好了,本質還是利用介面的多型特性。

    不過可以使用 google guava,裡面提供了一個增強的 Future 為 ListenableFuture。

    這裡引用 1 樓的例子,進行修改。

     class A implements FutureCallback{
            ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
            ListenableFuture futrue = service.submit(new Callable() {
                public User call() {
                    return heavyWork();
                }
            });
            Futures.addCallback(furtrue,this);
    
            public void onSuccess(User user) {
                //这个是回调执行的代码
            }
            public void onFailure(Throwable thrown) {
    
            }
        }

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-18 09:53:32

    非同步方法的「返回」在執行程式碼之前。程式碼都還沒執行,怎麼回傳結果?

    回覆
    0
  • 怪我咯

    怪我咯2017-04-18 09:53:32

    我覺得使用回呼方式也可以

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-18 09:53:32

    使用CountDownLatch 可以將非同步操作,轉換為同步操作。

    final CountDownLatch latch = new CountDownLatch(1);

    呼叫非同步方法。
    在非同步回呼結果中,
    latch.countDown();

    然後
    try {

    latch.await();
    

    } catch (InterruptedException e) {
    }

    return 資料;

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-18 09:53:32

    java裡有執行緒回傳Callable介面

    回覆
    0
  • 阿神

    阿神2017-04-18 09:53:32

    rx.java沒有接觸過
    但是我知道android裡的方法,希望對你有幫助。
    根據你所說,異步的返回結果用於主方法那麼就要考慮到線程間的通信
    即先寫一個handler , 並寫一個接收數據的方法,當數據過來時執行想要執行的方法
    然後子執行緒運行完成之後給handler發送資料即可。

    回覆
    0
  • 取消回覆