【问题标题】:Calling multiples webservices at same time using Java使用 Java 同时调用多个 Web 服务
【发布时间】:2018-07-22 02:07:38
【问题描述】:

我想在同一个方法中调用 3 个 web 服务,每个结果都将设置在一个对象中,如下面的代码:

public Dossie procuraPorCPF(String cpf) {

    Dossie dossie = new Dossie();

    // first webservice call
    dossie.setCnh(detectaClientCnh.verificaCNH(cpf));

    // second webservice call
    dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));

    // third webservice call
    dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    return dossie;
}

在上面的这种情况下,我调用了 3 个不同的 web 服务,它们每个大约需要 5 秒,然后继续使用这段代码不好。我想知道同时调用 3 个 Web 服务的最佳方法是什么,以及我如何使用此代码作为示例来做到这一点。我在这里搜索了一些文章甚至答案,但我不知道该怎么做。感谢您的耐心等待。

【问题讨论】:

  • 您可以生成一个单独的工作线程来处理每个 Web 服务调用。
  • 感谢您的评论,我该怎么做?我已经阅读了很多文章,但是有很多不同的实现,我仍然没有弄清楚哪一个是我的案例的最佳解决方案。
  • 看看here 让你开始思考这个问题。顺便说一句,我假设你没有使用 Android。
  • 不,我不知道,它是一个使用 Spring Boot 的 Web 应用程序

标签: java multithreading performance parallel-processing


【解决方案1】:

Java 中的并发是通过Thread 类处理的。 Thread 构造函数接受 Runnable 参数和运行 Thread 的代码。当调用start()方法时,JVM会创建新线程并执行Runnablerun()方法中的代码。

由于Runnable 只有一个抽象方法run(),您可以使用lambda expression 以获得更易读的代码。第一个调用我使用传统语法,另外两个调用使用 lambda 语法来演示这两种方法。

public Dossie procuraPorCPF(String cpf) {
    Dossie dossie = new Dossie();
    Thread[] threads = new Thread[3];

    threads[0] = new Thread(new Runnable() {
        @Override
        public void run() {
            dossie.setCnh(detectaClientCnh.verificaCNH(cpf));
        }
    };
    threads[0].start();

    threads[1] = new Thread(() ->
        dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
    threads[1].start();

    threads[2] = new Thread(() ->
        dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());
    threads[2].start();

    try {
        threads[0].join();
        threads[1].join();
        threads[2].join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    return dossie;
}

join() 方法阻止程序执行,直到调用 Thread 完成运行。通过将join()s 放在方法的末尾,可以保证在返回之前所有3 个请求都已完成。如果在您返回之前这些请求是否已完成并不重要,您可以简单地删除 join()s,然后请求将在后台继续运行,同时您的应用程序的其余部分运行。

对于较大的应用程序,Java 还包括 thread pools,它将为您管理 Threads 的创建。由于您的应用程序仅在本地上下文中使用相同的 3 个 Runnables,因此我认为上述解决方案更适合(并且对于此答案而言更具教育意义)。

【讨论】:

  • 谢谢,这段代码可以解决我的问题。您能否演示如何使用 Java8 功能(如 Future、FutureTask、Callable...)来做同样的事情?
  • 看来@Pankaj 已经打败了我
【解决方案2】:

您可以使用 ExecutorService 提交 Callable 并调用 Future.get() 来检索结果,如下所示(将 Future 更改为适当的返回值)。您还应该考虑错误处理和在方法之外创建线程池(如果可能在应用启动时)。

public Dossie procuraPorCPF(String cpf) {

    ExecutorService executor = Executors.newFixedThreadPool(3);

    Future<String> cnh = executor.submit(() -> detectaClientCnh.verificaCNH(cpf));
    Future<String> fotoCnh = executor.submit(() -> detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
    Future<String> pm =
        executor.submit(() -> consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    Dossie dossie = new Dossie();

    try {
      dossie.setCnh(cnh.get());
      dossie.setFotoCnh(fotoCnh.get());
      dossie.setPm(pm.get());
    } catch (InterruptedException | ExecutionException cause) {
      cause.printStackTrace();
    }
    executor.shutdown();
    return dossie;
  }

【讨论】:

    【解决方案3】:

    我在晚上开始写这个答案,然后把它留到第二天。到早上,给出了两个答案,其中一个被 OP 接受。将这个答案留给任何希望查看实现的完整设计和想法的人,而不是实际代码。


    设计:

    由于 Web 服务调用需要时间来响应,它们被异步调用,这意味着主线程与这些调用不同步。

    因此,它们的设计使您可以在单独的线程上进行单独的调用。

    对于您的情况,重要的 Java 元素是:

    1. Callable Interface;
    2. Future Interface;
    3. ExecutorService

    实施:

    1. 实现一个类,该类扩展实现了 Callable 接口,并在 call() 方法中包含 Web 服务的调用代码。
      • 对所有三个 Web 服务调用执行此操作;
    2. 启动一个 ExecutorService,它将为您执行此调用和结果收集;
    3. 当您必须进行调用时,创建三个调用的实例并将它们存储在 ArrayList 中;
    4. 使用您在第 2 步中创建的 ExecutorService,调用您在第 3 步中创建的实例。

    奖励步骤:在我看来,三个 Web 服务调用需要以相同的顺序重复进行(我不懂语言 - 它不是英语)。对于这样的代码,可以在实现的步骤 1 中创建的类的顶部创建一个单独的协调器类。

    这个编排器类可以扩展 Thread 类并进行三个 Web 服务调用。现在,这一类可以异步运行,而不是进行三个 Web 服务调用。保持代码模块化并抽象出复杂性。

    【讨论】:

    • 一点背景知识:我写这个答案不仅是为了回答 OP 的问题,也是为了记录我为一个非常相似的问题所做的设计,我解决了一个带回家的面试任务。这是一个Multi-threaded Word Count
    • 您的回答非常有用。在我发布的这个示例中,调用 webservices 的顺序无关紧要,但我将有一个新的实现,我需要等待一个特定调用的响应,然后再调用另一个 webservices。跨度>
    猜你喜欢
    • 2013-04-23
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 2014-05-04
    • 1970-01-01
    • 2016-09-05
    相关资源
    最近更新 更多