Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用带有返回值的同步方法包装一系列异步调用_Java_Asynchronous_Concurrency_Synchronous - Fatal编程技术网

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

Java 使用带有返回值的同步方法包装一系列异步调用,java,asynchronous,concurrency,synchronous,Java,Asynchronous,Concurrency,Synchronous,我当前的代码使用了一系列异步进程,这些进程最终会产生结果。我需要以这样一种方式包装它们,即每个都由一个同步方法访问,结果作为返回值。我想使用executor服务来实现这一点,以便允许许多这样的事情同时发生。我觉得未来可能与我的实现有关,但我想不出一个好方法来实现这一点 我现在所拥有的: public class DoAJob { ResultObject result; public void stepOne() { // Passes self in for a callba

我当前的代码使用了一系列异步进程,这些进程最终会产生结果。我需要以这样一种方式包装它们,即每个都由一个同步方法访问,结果作为返回值。我想使用executor服务来实现这一点,以便允许许多这样的事情同时发生。我觉得未来可能与我的实现有关,但我想不出一个好方法来实现这一点

我现在所拥有的:

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()调用来破坏代码。