CompletableFuture.allOf()在单个期货之后未完成

edr*_*edr 2 java completable-future

如javadoc中所述,当我使用CompletableFuture.allOf()组合独立的可完成期货时,在将所有期货提供给该方法之后,它不能可靠地完成。例如:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Runnable dummyTask = () -> {
            try {
                Thread.sleep(200);
            } catch (InterruptedException ignored) {
            }
        };

        CompletableFuture<Void> f1 = CompletableFuture.runAsync(dummyTask);
        CompletableFuture<Void> f2 = CompletableFuture.runAsync(dummyTask);
        CompletableFuture[] all = {f1, f2};
        f1.whenComplete((aVoid, throwable) -> System.out.println("Completed f1"));
        f2.whenComplete((aVoid, throwable) -> System.out.println("Completed f2"));
        CompletableFuture<Void> allOf = CompletableFuture.allOf(all);
        allOf.whenComplete((aVoid, throwable) -> {
                    System.out.println("Completed allOf");
                }
        );
        allOf.join();
        System.out.println("Joined");
    }
}
Run Code Online (Sandbox Code Playgroud)

导致以下结果:

Completed f2
Joined
Completed allOf
Completed f1
Run Code Online (Sandbox Code Playgroud)

我希望日志记录“ Joined”和“ Completed allOf”将在“ Completed f1”和“ Completed f2”之后编写。使事情变得更加混乱,期货的顺序似乎是头等大事。如果我换了线

CompletableFuture[] all = {f1, f2};
Run Code Online (Sandbox Code Playgroud)

CompletableFuture[] all = {f2, f1};
Run Code Online (Sandbox Code Playgroud)

结果输出变为:

Completed allOf
Completed f1
Completed f2
Joined
Run Code Online (Sandbox Code Playgroud)

更糟糕的是,如果我多次运行完全相同的代码,顺序将再次更改。我可以理解,“ f1”和“ f2”的顺序是随机变化的,对于“ allOf”和“ Joined”也是如此。但这确实令人惊讶。

如果很重要:这是Windows 7上的JDK 1.8.0_91。

fgb*_*fgb 5

f1.whenComplete会返回一个独立于的新未来f1AllOf将等待f1完成,但不会等待传递的lambda whenComplete完成。为了获得想要的结果,您可以尝试以下操作:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Runnable dummyTask = () -> {
            try {
                Thread.sleep(200);
            } catch (InterruptedException ignored) {
            }
        };

        CompletableFuture<Void> f1 = CompletableFuture.runAsync(dummyTask);
        CompletableFuture<Void> f2 = CompletableFuture.runAsync(dummyTask);
        f1 = f1.whenComplete((aVoid, throwable) -> System.out.println("Completed f1"));
        f2 = f2.whenComplete((aVoid, throwable) -> System.out.println("Completed f2"));
        CompletableFuture[] all = {f1, f2};
        CompletableFuture<Void> allOf = CompletableFuture.allOf(all);
        allOf.whenComplete((aVoid, throwable) -> {
            System.out.println("Completed allOf");
        });
        allOf.join();
        System.out.println("Joined");
    }
}
Run Code Online (Sandbox Code Playgroud)