Java 8中的completableFuture是否可扩展到多个内核?

时间:2016-06-02 03:36:03

标签: java multithreading java-8 completable-future

假设我有一个线程调用返回completablefuture的一堆方法,并说我将所有这些添加到列表中,最后我做了completablefutures.allof(list_size).join())。现在列表中的期货可以扩展到多个核心吗?换句话说是将期货安排到多个核心以利用并行性?

3 个答案:

答案 0 :(得分:10)

CompletableFuture表示与某些Executor相关联的任务。如果您没有明确指定执行程序(例如,您使用CompletableFuture.supplyAsync(Supplier)而不是CompletableFuture.supplyAsync(Supplier, Executor)),则使用公共ForkJoinPool作为执行程序。此池可以通过ForkJoinPool.commonPool()获取并且默认情况下,它会创建与您的系统所拥有的许多线程一样多的线程(通常是内核数量,如果您的内核支持超线程,则会加倍)。所以一般来说,是的,如果您使用所有默认值,那么多个内核将用于您的可更新期货。

答案 1 :(得分:2)

CompletableFuture本身未安排到线程(或核心)。任务是。要实现并行性,您需要创建多个任务。如果返回CompletableFuture的方法提交了像

这样的任务
  

返回CompletableFuture.supplyAsync(this :: calculate);

然后启动多个任务。 如果他们只是像

那样创建CompletableFuture
  

返回新的CompletableFuture();

然后没有任务启动,也没有并行性存在。

CompletableFuture {handle,thenCombine,thenCompose,thenApply}创建的CompletableFuture对象未连接到并行任务,因此并行性不会增加。

CompletableFuture创建的CompletableFuture对象{handleAsync,thenCombineAsync,thenComposeAsync,thenApplyAsync}连接到并行任务,但这些任务严格在与this CompletableFuture对象相对应的任务之后执行,因此无法提高并行性。

答案 2 :(得分:2)

拥有一堆CompletableFuture s并没有告诉你如何完成它们。

有两种完成方式:

  • 在一个实例上通过cancelcompletecompleteExceptionallyobtrudeExceptionobtrudeValue明确指出,或通过{获取未来{3}}静态方法

  • 隐含,通过执行提供的函数,无论是正常还是异常返回,还是通过完成前一个未来

    例如:

      如果前一个未来正常完成,
    • completedFuture正常完成而不运行提供的函数

    • 除了exceptionallyhandle及其*Async变体之外,其他所有链接方法都会异常完成,而不会运行所提供的函数(如果以前的未来或之前的任何一个)合并(*Both**Combine**Either*)方法中的期货,异常完整

    • 否则,当提供的函数正常或异常运行并完成时,将来就会完成

如果您拥有的未来是在没有功能的情况下创建的,或者它们没有被链接到另一个未来,或者换句话说,如果它们没有关联的功能,那么它们只会明确地完成,因此它会使如果这种可以完善的未来运行是没有意义的,更不用说如果他们可以使用多个线程了。

另一方面,如果期货有一个函数,则取决于它们的创建方式:

  • 如果它们都是独立的并使用ForkJoinPool.commonPool()(或缓存的线程池或类似的)作为执行程序,那么它们可能会并行运行,可能使用与数字一样多的活动线程核心

  • 如果他们彼此都有依赖关系(除了一个)或者执行者是单线程的,那么他们将一次运行一个

  • 介于两者之间的任何内容都有效,例如:

    • 某些期货可能相互依赖,或者在其他内部未来您不知道

    • 某些未来可能是用例如whenComplete您将看到有限度的并发运行任务

调用a fixed thread pool executor不会告诉未来开始运行,它只是等待它完成。

所以,最后回答你的问题:

  • 如果未来有关联的功能,那么它可能已经在运行,它可能会也可能不会运行其功能,具体取决于它的链接方式和前一个未来的完成情况,如果它未来可能会运行没有功能,或者它是否有机会运行其功能

  • 已经运行或将要运行的期货会这样做:

    • 在使用*Async方法链接时或使用*Async静态方法创建执行程序时提供的执行程序

    • 使用ForkJoinPool.commonPool()方法链接时*Async或使用不带执行程序的*Async静态方法创建时

    • 在没有*Async方法链接的情况下完成与他们所依赖的未来相同的线程,以防未来尚未完成

    • 在当前线程中,如果在没有*Async方法链接的情况下,他们所依赖的未来已经完成

在我看来,明确的完成方法应该被隔离到例如CompletionSource界面,例如CompletableFutureSource类实现它并提供未来,就像.NET在TaskCompletionSourceTask之间的关系一样。

就像现在一样,很可能你可以用一种非原定的方式完成它们来篡改你所拥有的可完成的未来。因此,在公开公开之后,不应使用CompletableFuture;从那时起,它就是您的API用户的CompletableFuture