我当前的代码使用一系列异步流程,最终导致结果。我需要以这样的方式包装每一个,每个都通过同步方法访问,结果作为返回值。我想使用执行程序服务来执行此操作,以便允许其中许多服务同时发生。我觉得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 ???
}
有没有人对如何优雅地实现这个有很好的想法?
答案 0 :(得分:7)
如果要将异步操作(完成后执行回调)转换为同步/阻塞操作,则可以使用阻塞队列。如果愿意,可以将它包装在Future对象中。
定义一个只能容纳一个元素的阻塞队列:
BlockingQueue<Result> blockingQueue = new ArrayBlockingQueue<Result>(1);
启动异步过程(将在后台运行),并编写回调,以便在完成后将其结果添加到阻塞队列。
在您的前台/应用程序线程中,让它从队列中取出(),直到元素可用为止:
Result result = blockingQueue.take();
我之前用类似Future的东西编写了类似的东西(前台线程需要阻止来自远程机器的异步响应),你可以找到示例代码here。
答案 1 :(得分:1)
我和Guava图书馆做过类似的事情;这些链接可能会指向正确的方向:
Is it possible to chain async calls using Guava?
https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained
答案 2 :(得分:0)
我建议使用invokeAll(..)。它将向执行程序提交一组任务,并阻塞直到最后一个完成(成功/异常)。然后它返回一个已完成的Future对象列表,这样你就可以循环它们并将结果合并到一个ResultObject中。
如果您希望以同步方式只运行单个任务,则可以使用以下命令:
executor.invokeAll(Collections.singleton(task));
- 编辑 -
现在我想我更了解你的需求。我假设你需要一种方法来提交独立的任务序列。请查看我在this answer中发布的代码。
答案 3 :(得分:0)
如果你想亲自动手,你可以这样做
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
不是线程安全的 - 如果两个线程同时调用stepOne
,则会出现问题。
答案 4 :(得分:0)
Bumerang是我唯一的异步http请求库,该库是使用Java-> https://github.com/hanilozmen/Bumerang为Android http请求构建的。我需要拨打同步电话时不要碰我的图书馆。这是我完整的代码。 npgall的回答启发了我,谢谢!类似的方法将应用于各种异步库。
public class TestActivity extends Activity {
MyAPI api = (MyAPI) Bumerang.get().initAPI(MyAPI.class);
BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<Object>(1);
static int indexForTesting;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
getItems();
try {
Object response = blockingQueue.take(); // waits for the response
Log.i("TAG", "index " + indexForTesting + " finished. Response " + response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
t.start();
}
void getItems() {
Log.i("TAG", "index " + ++indexForTesting + " started");
api.getItems(new ResponseListener<Response<List<ResponseModel>>>() {
@Override
public void onSuccess(Response<List<ResponseModel>> response) {
List<ResponseModel> respModel = response.getResponse();
try {
blockingQueue.put(response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onError(Response<List<ResponseModel>> response) {
Log.i("onError", response.toString());
try {
blockingQueue.put(response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}