我有一个使用spring RestTemplate调用多个URL的服务。

为了提高性能,我想并行执行这些请求。我可以使用的两种选择是:

  • Java 8利用fork-join公共池
  • 的并行流
  • 使用隔离的线程池
  • 可完成的将来

    只是想知道在阻塞I / O调用中使用并行流是否是最佳实践?

    最佳答案

    ForkJoinPool对于执行IO工作不是理想的选择,因为您没有从窃取属性的工作中获得任何好处。如果您计划使用commonPool,而应用程序的其他部分也使用了ExecutorService,则可能会干扰它们。专用的线程池,例如AsyncRestTemplate,可能是这两者之间更好的解决方案。

    我想提出一些更好的建议。与其亲自编写所有异步包装代码,不如考虑使用Spring的 RestTemplate 。它包含在Spring Web库中,其API与RestTemplate几乎相同。

    Spring的中心类,用于异步客户端HTTP访问。
    公开与ListenableFuture类似的方法,但返回AsyncRestTemplate 包装而不是具体的结果。

    [...]

    注意:默认情况下,AsyncClientHttpRequestFactory依赖于标准JDK工具
    建立HTTP连接。您可以切换为使用其他HTTP
    库,例如Apache HttpComponents,Netty和OkHttp
    接受ListenableFuture的构造方法。

    CompletableFuture 实例可以通过 ListenableFuture::completable() 轻松转换为AsyncClientHttpRequestFactory实例。

    如Javadoc中所述,您可以通过指定CompletableFuture来控制要使用的异步机制。对于列出的每个库,都有许多内置的实现。在内部,其中一些库可能会执行您建议的操作,并在专用线程池上运行阻塞IO。其他,例如Netty(如果有内存),则使用非阻塞IO来运行连接。您可能会从中受益。

    然后由您自己决定如何减少结果。使用anyOf,您可以访问allOfAsyncRestTemplate帮助器以及任何组合实例方法。

    例如,

    URI exampleURI = URI.create("https://www.stackoverflow.com");
    
    AsyncRestTemplate template = new AsyncRestTemplate/* specific request factory*/();
    var future1 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
    var future2 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
    var future3 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
    
    CompletableFuture.allOf(future1, future2, future3).thenRun(() -> {
        // you're done
    });
    

    此后,不推荐使用WebClient,而推荐使用Spring Web Flux的 CompletableFuture 。这个API有很大的不同,因此我不再赘述(除非说它确实可以让您取回ojit_code)。

    10-05 22:48
    查看更多