链接一系列异步调用

cur*_*zen 11 java asynchronous

我有一系列异步操作

private void doSomething(){
  get("/something", new Callback(){
    void onComplete(String data){
      updateUi(something, data);           
      doSomethingElse();
    }
  });
}

private void doSomethingElse(){
  get("/something/else", new Callback(){
    void onComplete(String data){
      updateUi(somethingElse, data);
      doYetAnotherThing();
    }
  });
}

private void doYetAnotherThing(){
  get("/yet/another/thing", new Callback(){
    void onComplete(String data){
      updateUi(yetAnotherThing, data);
      allDone();
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

这几乎没有问题:

  1. 无法在其他地方重用任何回调,因为每个回调都与"下一步"有关
  2. 重新排序操作或插入另一个操作是非直观的,涉及到整个地方跳跃.

我已经查看了以下选项来缓解这种情况:

  1. ExecuterService#invokeAll - 我没有看到如何在不阻塞的情况下使用此解决方案.
  2. RxJava - 如果可以的话,我宁愿避免在我的应用程序中进行这种范式转换!
  3. 番石榴ListenableFutures及其transform方法.我看到这个在互联网坚果周围的几个地方提到我老实说,我不明白这将如何解决我的问题.

所以,问题是:在Java中链接一系列异步调用的好方法是什么?寻找适用于Java 7的解决方案,因为我需要这个Android应用程序.

Mar*_*o13 7

关于遇到此问题的实际意图和用例,肯定会有一些猜测。此外,它还不完全清楚是什么somethingsomethingElse以及yetAnotherThing是(他们来自哪里以及他们应该去)。

但是,根据您提供的信息,作为slartidan答案的补充(或更确切地说,是扩展或概括):您所描绘的这些虚拟调用之间的差异似乎是

  • String传递给get方法的参数
  • Callback被称为
  • 接下来执行哪种方法

您可以将这些部分分解:String参数和Callback可以作为参数传递给创建的通用方法Callable。只需将这些Callable对象按适当的顺序放入列表中,然后使用单个线程执行器服务将其全部执行即可简单地定义调用的顺序。

如您在main本示例的方法中所见,可以很容易地配置调用顺序:

import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ChainedAsyncTest {

    public static void main(String[] args) throws InterruptedException {
        ChainedAsyncTest t = new ChainedAsyncTest();
        ExecutorService e = Executors.newFixedThreadPool(1);
        e.invokeAll(Arrays.asList(
            t.call("/something", t.somethingCallback),
            t.call("/something/else", t.somethingElseCallback),
            t.call("/yet/another/thing", t.yetAnotherThingCallback),
            t.allDone()));
    }

    private Callback somethingCallback = new Callback() {
        @Override
        public void onComplete(String data) {
            updateUi("something", data);
        }
    };

    private Callback somethingElseCallback = new Callback() {
        @Override
        public void onComplete(String data) {
            updateUi("somethingElse", data);
        }
    };

    private Callback yetAnotherThingCallback = new Callback() {
        @Override
        public void onComplete(String data) {
            updateUi("yetAnotherThing", data);
        }
    };

    private Callable<Void> call(
        final String key, final Callback callback) {
        return new Callable<Void>() {
            @Override
            public Void call() {
                get(key, callback);
                return null;
            }
        };
    }

    private Callable<Void> allDone() {
        return new Callable<Void>() {
            @Override
            public Void call() {
                System.out.println("allDone");
                return null;
            }
        };
    }



    interface Callback
    {
        void onComplete(String data);
    }
    private void get(String string, Callback callback) {
        System.out.println("Get "+string);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        callback.onComplete("result of "+string);
    }
    private void updateUi(String string, String data) {
        System.out.println("UpdateUI of "+string+" with "+data);
    }

}
Run Code Online (Sandbox Code Playgroud)

(该示例使用invokeAll,直到执行完所有任务之前,它都会阻塞。这可以通过不同的方式解决,以使其在呼叫站点处真正处于非阻塞状态。主要思想是创建一个任务列表,这些任务均由相同的方法创建呼叫)

  • @curioustechizen关于*“真正异步和非阻塞” *:我假设调用/任务必须被阻塞,这意味着一个应该在另一个之后执行(否则,您在问题中勾勒的“链接”将是没有意义的)。因此,如果此“非阻塞” *仅表示完整的调用顺序:您可以将每个任务传递给ExecutorService#submit方法,而不是使用`invokeAll`来将任务分别提交给`ExecutorService`。 ,在“ for”循环中。然后,提交任务的线程将继续,并且任务将在后台处理 (2认同)