ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
### 结合 CompletableFuture 第二种类型的 `CompletableFuture` 方法采用两种 `CompletableFuture` 并以各异方式将它们组合在一起。就像两个人在比赛一样, 一个`CompletableFuture`通常比另一个更早地到达终点。这些方法允许你以不同的方式处理结果。 为了测试这一点,我们将创建一个任务,它有一个我们可以控制的定义了完成任务所需要的时间量的参数。 CompletableFuture 先完成: ```java // concurrent/Workable.java import java.util.concurrent.*; import onjava.Nap; public class Workable { String id; final double duration; public Workable(String id, double duration) { this.id = id; this.duration = duration; } @Override public String toString() { return "Workable[" + id + "]"; } public static Workable work(Workable tt) { new Nap(tt.duration); // Seconds tt.id = tt.id + "W"; System.out.println(tt); return tt; } public static CompletableFuture<Workable> make(String id, double duration) { return CompletableFuture .completedFuture( new Workable(id, duration) ) .thenApplyAsync(Workable::work); } } ``` 在 `make()`中,`work()`方法应用于`CompletableFuture`。`work()`需要一定的时间才能完成,然后它将字母W附加到id上,表示工作已经完成。 现在我们可以创建多个竞争的 `CompletableFuture`,并使用 `CompletableFuture` 库中的各种方法来进行操作: ```java // concurrent/DualCompletableOperations.java import java.util.concurrent.*; import static onjava.CompletableUtilities.*; public class DualCompletableOperations { static CompletableFuture<Workable> cfA, cfB; static void init() { cfA = Workable.make("A", 0.15); cfB = Workable.make("B", 0.10); // Always wins } static void join() { cfA.join(); cfB.join(); System.out.println("*****************"); } public static void main(String[] args) { init(); voidr(cfA.runAfterEitherAsync(cfB, () -> System.out.println("runAfterEither"))); join(); init(); voidr(cfA.runAfterBothAsync(cfB, () -> System.out.println("runAfterBoth"))); join(); init(); showr(cfA.applyToEitherAsync(cfB, w -> { System.out.println("applyToEither: " + w); return w; })); join(); init(); voidr(cfA.acceptEitherAsync(cfB, w -> { System.out.println("acceptEither: " + w); })); join(); init(); voidr(cfA.thenAcceptBothAsync(cfB, (w1, w2) -> { System.out.println("thenAcceptBoth: " + w1 + ", " + w2); })); join(); init(); showr(cfA.thenCombineAsync(cfB, (w1, w2) -> { System.out.println("thenCombine: " + w1 + ", " + w2); return w1; })); join(); init(); CompletableFuture<Workable> cfC = Workable.make("C", 0.08), cfD = Workable.make("D", 0.09); CompletableFuture.anyOf(cfA, cfB, cfC, cfD) .thenRunAsync(() -> System.out.println("anyOf")); join(); init(); cfC = Workable.make("C", 0.08); cfD = Workable.make("D", 0.09); CompletableFuture.allOf(cfA, cfB, cfC, cfD) .thenRunAsync(() -> System.out.println("allOf")); join(); } } ``` **输出结果**: ``` Workable[BW] runAfterEither Workable[AW] ***************** Workable[BW] Workable[AW] runAfterBoth ***************** Workable[BW] applyToEither: Workable[BW] Workable[BW] Workable[AW] ***************** Workable[BW] acceptEither: Workable[BW] Workable[AW] ***************** Workable[BW] Workable[AW] thenAcceptBoth: Workable[AW], Workable[BW] **************** Workable[BW] Workable[AW] thenCombine: Workable[AW], Workable[BW] Workable[AW] ***************** Workable[CW] anyOf Workable[DW] Workable[BW] Workable[AW] ***************** Workable[CW] Workable[DW] Workable[BW] Workable[AW] ***************** allOf ``` - 为了方便访问, 将 `cfA` 和 `cfB` 定义为 `static`的。 - `init()`方法用于 `A`, `B` 初始化这两个变量,因为 `B` 总是给出比`A`较短的延迟,所以总是 `win` 的一方。 - `join()` 是在两个方法上调用 `join()` 并显示边框的另一个便利方法。 - 所有这些 “`dual`” 方法都以一个 `CompletableFuture` 作为调用该方法的对象,第二个 `CompletableFuture` 作为第一个参数,然后是要执行的操作。 - 通过使用 `showr()` 和 `voidr()` 可以看到,“`run`”和“`accept`”是终端操作,而“`apply`”和“`combine`”则生成新的 `payload-bearing` (承载负载)的 `CompletableFuture`。 - 方法的名称不言自明,你可以通过查看输出来验证这一点。一个特别有趣的方法是 `combineAsync()`,它等待两个 `CompletableFuture` 完成,然后将它们都交给一个 `BiFunction`,这个 `BiFunction` 可以将结果加入到最终的 `CompletableFuture` 的有效负载中。