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

我当前的代码使用一系列异步进程,最终结果。 我需要以这样的方式包装每一个,每个都通过同步方法访问,结果作为返回值。 我想使用执行程序服务来执行此操作,以便允许许多这些服务同时发生。 我觉得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 } } 

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

 public ResultObject getResult(){ // ??? What goes here ??? } 

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

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

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

    BlockingQueue blockingQueue = new ArrayBlockingQueue(1);

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

  3. 在前台/应用程序线程中,让队列中的take()阻塞,直到元素变为可用:

    Result result = blockingQueue.take();

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

我和Guava图书馆做过类似的事情; 这些链接可能会指向正确的方向:

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

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

如果你想亲自动手,你可以这样做

 ResultObject result; public void stepOne() otherComponent.doStepOne(this); synchronized(this) while(result==null) this.wait(); return result; public void stepThree(ResultObject resultFromOtherComponent) result = resultFromOtherComponent; synchronized(this) this.notify(); 

或者您可以使用更高级别的并发工具,如BlockingQueue,Semaphore,CountdownLatch,Phaser等。

请注意, DoAJob不是线程安全的 – 如果两个线程同时调用stepOnestepOne出现问题。

我建议使用invokeAll(..) 。 它将向执行程序提交一组任务,并阻塞直到最后一个完成(成功/exception)。 然后,它返回已完成的Future对象的列表,因此您可以循环它们并将结果合并到单个ResultObject中。

如果您希望以同步方式只运行单个任务,则可以使用以下命令:

 executor.invokeAll(Collections.singleton(task)); 

– 编辑 –

现在我想我更了解你的需求。 我假设您需要一种方法来提交独立的任务序列。 请看一下我在这个答案中发布的代码。