Ba toán tử ghép khác nhau ở hình dạng hàm truyền vào:
thenApply(Function<T, U>)— biến đổi kết quả đồng bộ. Giốngmap.thenCompose(Function<T, CompletionStage<U>>)— hàm trả về một future khác, kết quả được làm phẳng. GiốngflatMap. DùngthenApplyở đây sẽ raCompletableFuture<CompletableFuture<U>>lồng nhau.thenCombine(other, BiFunction)— hai future chạy song song, độc lập, ghép kết quả khi cả hai xong.
java
CompletableFuture<User> user = fetchUser(id);
user.thenApply(User::name); // User -> String
user.thenCompose(u -> fetchOrders(u.id())); // User -> CF<List<Order>>, làm phẳng
user.thenCombine(fetchConfig(), Page::of); // chạy song song rồi gộpCallback chạy ở đâu: bản không có Async không đảm bảo thread nào. Nếu future chưa xong, callback chạy trên thread hoàn thành nó; nếu future đã xong sẵn, nó chạy ngay trên thread đang gọi. Bản *Async không truyền executor thì dùng ForkJoinPool.commonPool() — pool này mặc định chỉ có Ncpu - 1 thread và dùng chung toàn ứng dụng, nên đặt việc chặn (gọi HTTP, JDBC) vào đó sẽ làm nghẽn mọi tác vụ song song khác.
Với tác vụ IO, luôn truyền executor riêng: thenApplyAsync(fn, ioExecutor).