Java 链接一系列异步调用

Java 链接一系列异步调用,java,asynchronous,Java,Asynchronous,我有一系列异步操作 private void doSomething(){ get("/something", new Callback(){ void onComplete(String data){ updateUi(something, data); doSomethingElse(); } }); } private void doSomethingElse(){ get("/something/else", n

我有一系列异步操作

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();
    }
  });
}
这有几个问题:

  • 无法在其他地方重用任何回调,因为每个回调本质上都与“下一步”相关
  • 重新排序操作或插入另一个操作是不直观的,需要到处跳跃
  • 我已经研究了以下选项来缓解这一问题:

  • ExecuterService#invokeAll
    -我不知道如何在不阻塞的情况下使用此解决方案
  • 如果可以的话,我宁愿在我的应用程序中避免这种范式转换
  • 番石榴的
    ListenableFutures
    及其
    transform
    方法。我在interwebs的一些地方看到了这一点,老实说,我不认为这能解决我的问题

  • 所以,问题是:在Java中链接一系列异步调用的好模式是什么?寻找一个能与Java 7一起工作的解决方案,因为我需要一个Android应用程序。

    自发的想法:您可以将链接调用定义为一个方法参数,以使您的方法可重用。下面是我的示例代码:

    public class Scribble {
    
        final Callback step1 = new Callback() {
            void onComplete(String string) {
                doSomethingElse(step2);
            };
        };
    
        final Callback step2 = new Callback() {
            void onComplete(String string) {
                doYetAnotherThing(step3);
            };
        };
    
        final Callback step3 = new Callback() {
            void onComplete(String string) {
                allDone();
            }
        };
    
        private void start() {
            doSomething(step1);
        }
    
        private void doSomething(final Callback externalCallback) {
            get("/something", new Callback() {
                void onComplete(String data) {
                    updateUi(something, data);
                    externalCallback.onComplete(data);
                }
            });
        }
    
        private void doSomethingElse(final Callback externalCallback) {
            get("/something/else", new Callback() {
                void onComplete(String data) {
                    updateUi(somethingElse, data);
                    externalCallback.onComplete(data);
                }
            });
        }
    
        private void doYetAnotherThing(final Callback externalCallback) {
            get("/yet/another/thing", new Callback() {
                void onComplete(String data) {
                    updateUi(yetAnotherThing, data);
                    externalCallback.onComplete(data);
                }
            });
        }
    
        // - the code below is only to make everything compilable -
    
        public class Callback {
    
            void onComplete(String string) {
            }
    
        }
    
        private Object something;
        protected Object somethingElse;
        protected Object yetAnotherThing;
    
        protected void allDone() {
            System.out.println("Scribble.allDone()");
        }
    
        protected void updateUi(Object yetAnotherThing2, String data) {
            System.out.println("Scribble.updateUi()"+data);
        }
    
        private void get(String string, Callback callback) {
            System.out.println("get "+string);
            callback.onComplete(string);
        }
    
        public static void main(String[] args) {
            new Scribble().start();
        }
    
    }
    

    关于您遇到这个问题的实际意图和用例,肯定有一些猜测。此外,还不完全清楚什么是
    某物
    某物
    是另一物
    (它们来自哪里,应该去哪里)

    但是,根据您提供的信息,并且作为对的补充(或者更确切地说是扩展或泛化):您在那里绘制的这些伪调用之间的差异似乎是

    • 传递给
      get
      方法的
      String
      参数
    • 调用的
      回调
    • 下一步执行哪个方法
    您可以考虑这些部分:
    字符串
    参数和
    回调
    可以作为参数传递给创建
    可调用
    的常规方法。调用的顺序可以简单地通过将这些
    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);
        }
    
    }
    
    导入java.util.array;
    导入java.util.concurrent.Callable;
    导入java.util.concurrent.ExecutorService;
    导入java.util.concurrent.Executors;
    公共类链式同步测试{
    公共静态void main(字符串[]args)引发InterruptedException{
    ChainedAsyncTest t=新的ChainedAsyncTest();
    ExecutorService e=Executors.newFixedThreadPool(1);
    e、 invokeAll(Arrays.asList(
    t、 调用(“/something”,t.something callback),
    t、 调用(“/something/else”,t.somethingelescallback),
    t、 call(“/yet/other/thing”,t.yetAnotherThingCallback),
    t、 allDone());
    }
    私有回调somethingCallback=new Callback(){
    @凌驾
    公共void onComplete(字符串数据){
    更新(“某物”,数据);
    }
    };
    私有回调somethingElseCallback=new Callback(){
    @凌驾
    公共void onComplete(字符串数据){
    更新(“somethingElse”,数据);
    }
    };
    私有回调yetAnotherThingCallback=新回调(){
    @凌驾
    公共void onComplete(字符串数据){
    updateUi(“yetAnotherThing”,数据);
    }
    };
    私人呼叫(
    最终字符串键,最终回调){
    返回新的可调用(){
    @凌驾
    公开作废通知(){
    get(key,callback);
    返回null;
    }
    };
    }
    私有可调用的allDone(){
    返回新的可调用(){
    @凌驾
    公开作废通知(){
    System.out.println(“全部完成”);
    返回null;
    }
    };
    }
    接口回调
    {
    void onComplete(字符串数据);
    }
    私有void get(字符串、回调){
    System.out.println(“Get”+字符串);
    试一试{
    睡眠(500);
    }捕捉(中断异常e){
    e、 printStackTrace();
    }
    callback.onComplete(“结果”+字符串);
    }
    私有void updateUi(字符串、字符串数据){
    System.out.println(“用“+数据”更新“+字符串+”);
    }
    }
    

    (本例使用了
    invokeAll
    ,它会一直阻塞,直到所有任务都已执行。这可以通过不同的方式解决,在调用站点实现真正的非阻塞。其主要思想是创建一个任务列表,所有任务都是通过相同的方法调用创建的)

    我完全支持批准的答案,但我也在讨论我为这些类型的问题创建的东西,当您开始在异步操作链中添加条件逻辑时,这些问题会派上用场。我最近将其发酵成一个简单的库()

    下面是您如何连接示例的。如您所见,每个任务都不知道接下来的任务。与批准的答案相反,任务的链接是通过一个简单的同步(…外观)方法体而不是列表来完成的

    public void doChainedLogic() {
    
        final AsyncTask<Void, Void> doSomething = new AsyncTask<Void, Void>() {
            @Override
            public void run(Void arg, final ResultHandler<Void> resultHandler) {
                get("/something", new Callback() {
                    public void onComplete(String data) {
                        updateUi(something, data);
                        resultHandler.reportComplete();
                    }
                });
            }
        };
    
        final AsyncTask<Void, Void> doSomethingElse = new AsyncTask<Void, Void>() {
            @Override
            public void run(Void arg, final ResultHandler<Void> resultHandler) {
                get("/something/else", new Callback() {
                    public void onComplete(String data) {
                        updateUi(somethingElse, data);
                        resultHandler.reportComplete();
                    }
                });
            }
        };
    
        final AsyncTask<Void, Void> doYetAnotherThing = new AsyncTask<Void, Void>() {
            @Override
            public void run(Void arg, final ResultHandler<Void> resultHandler) {
                get("/yet/another/thing", new Callback() {
                    public void onComplete(String data) {
                        updateUi(yetAnotherThing, data);
                        resultHandler.reportComplete();
                    }
                });
            }
        };
    
        // This looks synchronous, but behind the scenes JasyncDriver is
        // re-executing the body and skipping items already executed.
        final JasyncDriver driver = new JasyncDriver();
        driver.execute(new DriverBody() {
            public void run() {
                driver.execute(doSomething);
                driver.execute(doSomethingElse);
                driver.execute(doYetAnotherThing);
            }
        });
    }
    
    public void docainedlogic(){
    final AsyncTask doSomething=new AsyncTask(){
    @凌驾
    公共作废运行(作废参数,最终结果删除器结果删除器){
    获取(“/something”,新回调(){
    公共void onComplete(字符串数据){
    更新(某物、数据);
    resultHandler.reportComplete();
    }
    });
    }
    };
    final AsyncTask doSomethingElse=new AsyncTask(){
    @凌驾
    公共作废运行(作废参数,最终结果删除器结果删除器){
    获取(“/something/else”,新回调(){
    
    final AsyncTask<Void, String> checkSomething = new AsyncTask<Void, String>() {
        @Override
        public void run(Void arg, final ResultHandler<String> resultHandler) {
            get("/check/something", new Callback() {
                public void onComplete(String data) {
                    resultHandler.reportComplete(data);
                }
            });
        }
    };
    
    final JasyncDriver driver = new JasyncDriver();
    driver.execute(new DriverBody() {
        public void run() {
            driver.execute(doSomething);
            if ("foobar".equals(driver.execute(checkSomething))) {
                driver.execute(doSomethingElse);
            }
            driver.execute(doYetAnotherThing);
        }
    });