【问题标题】:Get result from call that doesn't return result?从不返回结果的调用中获取结果?
【发布时间】:2016-03-21 21:40:48
【问题描述】:

我使用的 API 调用结果,但不返回结果本身。一旦进行调用,就会调用一个单独的方法(侦听器),其中包含结果。这是我想要实现的一个示例:

public static void main (String[] args) {
    Object obj = someMethod();

    System.out.println("The object is" + obj + ", wooh!");
}

public void callObject() {
    // This is the call that sends a request for the object
}

public void receiveObject(Object object) {
    // This is the API method that is invoked with the result (cannot be changed)
}

// What I want to be able to do
public Object someMethod() {
    callObject();
    // return received object once received, but how?
}

callObject() 不返回对象,仅启动对它的检索。我想要一个调用对象的方法,然后在收到它时返回它。我一直在研究 Callables 和 Future 结果,但我不确定如何实现它们。

有什么想法吗?谢谢!

【问题讨论】:

  • 你的问题不清楚。
  • 这应该是非阻塞的吗?一种常见的解决方案是将callback 对象传递给callObject 方法。
  • @Perdomoff 我将进行编辑,请耐心等待。
  • @ElliottFrisch 在其他任务应该能够同时运行(单独的线程)的意义上它是非阻塞的,但是可以在等待结果时对结果进行引用(例如System.out.println)
  • 为了返回由callObject() 获取的ObjectcallObject() 自然也需要返回Object。那么someMethod() 可以简单地使用return callObject();,除非您需要先执行其他操作。

标签: java concurrency future callable futuretask


【解决方案1】:

最简单的情况:您以普通阻塞方式发送请求,并希望能够在主线程上执行某些操作。为此,请使用 ExecutorService,通常通过调用 Executors 创建,例如:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class ToyConc1 {
    public static void main(String[] args) throws InterruptedException,
            ExecutionException {
        ExecutorService exec = Executors.newCachedThreadPool();
        try {
            Callable<String> op1 = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return slowlyGetHttpPage("http://www.google.com");
                }
            }; 
            Callable<String> op2 = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return slowlyGetHttpPage("http://edition.cnn.com/");
                }
            }; 
            Future<String> resF1 = exec.submit(op1);
            Future<String> resF2 = exec.submit(op2);

            for (int i = 0; i < 20; i++) {
                System.out.println("doing useful work on the main thread...");
            }
            System.out.println("The object 1 is " + limit(resF1.get(), 1000) + ", wooh!");
            System.out.println("The object 2 is " + limit(resF2.get(), 1000) + ", wooh!");
        } finally {
            exec.shutdown();
            exec.awaitTermination(60, TimeUnit.SECONDS);
        }
    }

    private static String slowlyGetHttpPage(String urlName) throws InterruptedException,
            IOException {
        Thread.sleep(2000);
        URL url = new URL(urlName);
        URLConnection conn = url.openConnection();
        InputStream in = conn.getInputStream();
        InputStreamReader reader = new InputStreamReader(in); // wrong charset maybe
        BufferedReader br = new BufferedReader(reader);
        StringBuilder sb = new StringBuilder();
        try {
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } finally {
            br.close();
        }
    }

    private static String limit(String s, int length) {
        if (s == null) {
            return null;
        }
        if (s.length() <= length) {
            return s;
        }
        return s.substring(0, length) + " [and " + (s.length() - length) + " more]";
    }
}

或者,您用于发送请求和返回结果的库/框架/技术可能已经为您提供了类似Future 的信息或接受类似回调的信息(例如,AsyncHttpClient 两者都有)。

【讨论】:

    【解决方案2】:

    这个怎么样。在您的班级中引入一个新字段:

    private Object result;
    

    然后在你设置的receiveObject(Object object)方法中:

    this.result = object;
    

    在 someMethod() 中:

    callObject();
    while(this.result==null) {
        Thread.sleep(100);
    }
    Object answer = this.result;
    this.result = null;
    return answer;
    

    应该可以正常工作,只要您为每个 API 请求创建此类的新实例。不要试图让这个类成为单例,它只会让事情变得不必要的复杂。

    如果您真的需要一个单例,您可以将 private Object result; 概括为一个映射,并想办法识别每个单独的 API 调用,例如使用一些调用者 ID。

    最后,您还可以将private Object result; 替换为java.util.concurrent.CompletableFuture。然后在receiveObject 方法中完成那个未来并在someMethod 中等待它(.get() 它)。这会比使用线程睡眠循环更惯用一点。

    【讨论】:

      【解决方案3】:

      怎么可能返回没有任何东西要返回的东西,在someMethod() 那里是return 字,而callObject() 什么都不返回,因为它是void。这样会返回一个对象

      public Object someMethod() {
          return new Object();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-11
        • 2015-07-15
        • 2018-09-24
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        • 2016-01-16
        • 2016-09-27
        相关资源
        最近更新 更多