Java 使用带有返回值的同步方法包装一系列异步调用
我当前的代码使用了一系列异步进程,这些进程最终会产生结果。我需要以这样一种方式包装它们,即每个都由一个同步方法访问,结果作为返回值。我想使用executor服务来实现这一点,以便允许许多这样的事情同时发生。我觉得未来可能与我的实现有关,但我想不出一个好方法来实现这一点 我现在所拥有的:Java 使用带有返回值的同步方法包装一系列异步调用,java,asynchronous,concurrency,synchronous,Java,Asynchronous,Concurrency,Synchronous,我当前的代码使用了一系列异步进程,这些进程最终会产生结果。我需要以这样一种方式包装它们,即每个都由一个同步方法访问,结果作为返回值。我想使用executor服务来实现这一点,以便允许许多这样的事情同时发生。我觉得未来可能与我的实现有关,但我想不出一个好方法来实现这一点 我现在所拥有的: public class DoAJob { ResultObject result; public void stepOne() { // Passes self in for a callba
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 ???
}
有人对如何优雅地实现这一点有好的想法吗?我对番石榴库做了类似的工作;这些链接可能会为您指明正确的方向: 我建议使用。它将向执行者提交一组任务,并阻止,直到最后一个任务完成(成功/异常)。然后,它返回一个已完成的未来对象列表,这样您就可以对它们进行循环,并将结果合并到单个ResultObject中 如果希望以同步方式仅运行单个任务,可以使用以下方法:
executor.invokeAll(Collections.singleton(task));
--编辑--
现在我想我更了解你的需要了。我假设您需要一种方法来提交独立的任务序列。请看一下我发布的代码。如果要将异步操作(完成后执行回调)转换为同步/阻塞操作,可以使用阻塞队列。如果愿意,可以将其包装到未来的对象中
BlockingQueue BlockingQueue=newarrayblockingqueue(1)代码>
Result=blockingQueue.take()代码>
我以前写过类似的东西(前台线程需要阻止来自远程机器的异步响应),使用类似于Future的东西,你可以找到示例代码。如果你想弄脏你的手,你可以这样做
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();
或者您可以使用更高级别的并发工具,如阻塞队列、信号量、倒计时闩锁、相位器等
请注意,
DoAJob
不是线程安全的-如果两个线程同时调用stepOne
,则会出现故障。Bumerang是我的仅异步http请求库,它是为使用Java->的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();
}
}
});
}
公共类测试活动扩展活动{
MyAPI=(MyAPI)Bumerang.get().initAPI(MyAPI.class);
BlockingQueue BlockingQueue=新阵列BlockingQueue(1);
静态内索引;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_测试);
线程t=新线程(新的可运行线程(){
@凌驾
公开募捐{
对于(int i=0;i<10;i++){
getItems();
试一试{
Object response=blockingQueue.take();//等待响应
Log.i(“TAG”、“index”+indexForTesting+“finished.Response”+Response.toString());
}捕获(例外e){
e、 printStackTrace();
}
}
}
});
t、 start();
}
void getItems(){
Log.i(“标记”、“索引”+++indexForTesting+“已启动”);
api.getItems(新的ResponseListener(){
@凌驾
成功时公共无效(响应){
List respModel=response.getResponse();
试一试{
blockingQueue.put(响应);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
@凌驾
公共无效申报人(回复){
Log.i(“onError”,response.toString());
试一试{
blockingQueue.put(响应);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
});
}
}本规范中缺少一点:您计划如何在最后将不同任务的ResultObject组合成一个单独的任务?我不确定我是否理解这个问题。通常,该过程由新的DoAJob.stepOne()启动;stepTwo()方法由来自otherComponent的回调启动。在回调链的末尾,正确填充ResultObject。任何中间数据位都会集成到最终结果中。我在示例中没有很好地说明这一点,但步骤取决于前一步的完成情况。例如,Step2()在远程完成Step2()时执行。stepTwo()本质上是在stepOne()中调用的组件的完成回调。
SynchronousQueue
可能更适合这个目的。恐怕我以前去过那里(实际上我链接的代码)。SynchronousQueue可能会导致后台线程阻塞或接收异常,如果存在争用条件,使得后台线程在前台线程take()之前完成。如果如OP所述,这是在将来包装的,那么如果应用程序在调用Future.get()之前做了一些其他工作,这可能是很常见的情况。是的,我可能最终不得不这样做,因为这似乎是一个相当具体的用例和体系结构。我希望避免实现wait()循环,或者用太多的synchronized()调用来破坏代码。