使用带有返回值的同步方法包装一系列异步调用

iro*_*ill 9 java concurrency asynchronous synchronous

我当前的代码使用一系列异步过程,最终达到结果.我需要以这样的方式包装每一个,每个都通过同步方法访问,结果作为返回值.我想使用执行程序服务来执行此操作,以便允许其中许多服务同时发生.我觉得Future可能与我的实现相关,但我无法找到一个很好的方法来实现这一点.

我现在拥有的:

public class DoAJob {
  ResultObject result;

  public void stepOne() {
    // Passes self in for a callback
    otherComponent.doStepOne(this);
  }

  // Called back by otherComponent once it has completed doStepOne
  public void stepTwo(IntermediateData d) {
    otherComponent.doStepTwo(this, d);
  }

  // Called back by otherComponent once it has completed doStepTwo
  public void stepThree(ResultObject resultFromOtherComponent) {
    result = resultFromOtherComponent;
  //Done with process
  }
}
Run Code Online (Sandbox Code Playgroud)

这在内部工作得非常好,但现在我需要将我的进程映射到具有返回值的同步方法,如:

public ResultObject getResult(){
  // ??? What goes here ???
}
Run Code Online (Sandbox Code Playgroud)

有没有人对如何优雅地实现它有一个好主意?

npg*_*all 7

如果要将异步操作(完成后执行回调)转换为同步/阻塞操作,则可以使用阻塞队列.如果您愿意,可以将其包装在Future对象中.

  1. 定义一个只能容纳一个元素的阻塞队列:

    BlockingQueue<Result> blockingQueue = new ArrayBlockingQueue<Result>(1);

  2. 启动异步进程(将在后台运行),并编写回调,以便在完成后将其结果添加到阻塞队列.

  3. 在前台/应用程序线程中,让它从队列中取出(),阻塞直到元素可用:

    Result result = blockingQueue.take();

我之前用类似Future的东西编写了类似的东西(前台线程需要阻止来自远程机器的异步响应),你可以在这里找到示例代码.

  • 在我害怕之前我一直在那里(实际上与我链接的代码).如果存在竞争条件,后台线程在前台线程调用take()之前完成,则SynchronousQueue可能导致后台线程阻塞或接收异常.如果在OP中提到它包含在Future中,那么在调用Future.get()之前应用程序执行其他工作可能会很常见. (2认同)

小智 1

我对 Guava 库做了类似的事情;这些链接可能会为您指明正确的方向:

是否可以使用 Guava 链接异步调用?

https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained