Bài 4: Kết hợp nhiều CompletableFuture
Trong bài viết này, chúng ta sẽ tìm hiểu cách kết hợp nhiều CompletableFuture để thực hiện các tác vụ đồng thời hoặc theo chuỗi. Chúng ta sẽ khám phá các phương thức quan trọng như thenCompose, thenCombine, allOf, và anyOf. Mỗi phương thức sẽ được giải thích chi tiết cùng với các ví dụ minh họa cụ thể.
thenCompose và thenCombine
thenCompose
Phương thức thenCompose được sử dụng để kết hợp hai CompletableFuture theo kiểu chuỗi, nơi CompletableFuture thứ hai phụ thuộc vào kết quả của CompletableFuture thứ nhất. Nó cho phép bạn tạo một pipeline của các tác vụ không đồng bộ.
Cú pháp:
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
Ví dụ:
import java.util.concurrent.CompletableFuture;
public class ThenComposeExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
future.thenAccept(result -> {
System.out.println("Result: " + result); // Result: Hello World
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Trong ví dụ này:
CompletableFuture.supplyAsynctạo một tác vụ trả về chuỗi "Hello".thenComposetạo mộtCompletableFuturemới dựa trên kết quả của tác vụ trước, thêm " World" vào chuỗi.thenAcceptin ra kết quả cuối cùng.
thenCombine
Phương thức thenCombine được sử dụng để kết hợp kết quả của hai CompletableFuture độc lập và trả về kết quả cuối cùng. Nó nhận hai CompletableFuture và một BiFunction để kết hợp kết quả của chúng.
Cú pháp:
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
Ví dụ:
import java.util.concurrent.CompletableFuture;
public class ThenCombineExample {
public static void main(String[] args) {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 2);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 3);
CompletableFuture<Integer> resultFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);
resultFuture.thenAccept(result -> {
System.out.println("Result: " + result); // Result: 5
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Trong ví dụ này:
CompletableFuture.supplyAsynctạo hai tác vụ độc lập trả về các giá trị 2 và 3.thenCombinekết hợp kết quả của hai tác vụ, cộng hai giá trị lại với nhau.thenAcceptin ra kết quả cuối cùng.
allOf và anyOf
allOf
Phương thức allOf được sử dụng để kết hợp nhiều CompletableFuture và tạo ra một CompletableFuture hoàn thành khi tất cả các CompletableFuture trong tập hợp hoàn thành. Nó không trả về kết quả của các CompletableFuture đã kết hợp mà chỉ báo hiệu rằng tất cả chúng đã hoàn thành.
Cú pháp:
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
Ví dụ:
import java.util.concurrent.CompletableFuture;
public class AllOfExample {
public static void main(String[] args) {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("Task 1 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("Task 2 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("Task 3 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
allFutures.thenRun(() -> System.out.println("All tasks completed"));
try {
allFutures.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Trong ví dụ này:
Ba
CompletableFutuređộc lập thực hiện các tác vụ không đồng bộ với các thời gian chờ khác nhau.CompletableFuture.allOfkết hợp cả baCompletableFuturevà tạo mộtCompletableFuturehoàn thành khi tất cả các tác vụ hoàn thành.thenRunin ra "All tasks completed" khi tất cả các tác vụ hoàn thành.
anyOf
Phương thức anyOf được sử dụng để kết hợp nhiều CompletableFuture và tạo ra một CompletableFuture hoàn thành khi bất kỳ CompletableFuture nào trong tập hợp hoàn thành. Nó trả về kết quả của CompletableFuture hoàn thành đầu tiên.
Cú pháp:
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
Ví dụ:
import java.util.concurrent.CompletableFuture;
public class AnyOfExample {
public static void main(String[] args) {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("Task 1 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("Task 2 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("Task 3 completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2, future3);
anyFuture.thenAccept(result -> System.out.println("First task completed"));
try {
anyFuture.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Trong ví dụ này:
Ba
CompletableFutuređộc lập thực hiện các tác vụ không đồng bộ với các thời gian chờ khác nhau.CompletableFuture.anyOfkết hợp cả baCompletableFuturevà tạo mộtCompletableFuturehoàn thành khi bất kỳ tác vụ nào hoàn thành trước.thenAcceptin ra "First task completed" khi một trong các tác vụ hoàn thành.
Kết Luận
Trong bài viết này, chúng ta đã tìm hiểu cách kết hợp nhiều CompletableFuture để thực hiện các tác vụ đồng thời hoặc theo chuỗi bằng cách sử dụng các phương thức thenCompose, thenCombine, allOf, và anyOf. Các phương thức này cho phép bạn xây dựng các pipeline tác vụ không đồng bộ phức tạp và quản lý kết quả của chúng một cách hiệu quả.
Bài Tập Thực Hành
Sử dụng
thenComposeđể kết hợp haiCompletableFuturetheo kiểu chuỗi, nơi tác vụ thứ hai phụ thuộc vào kết quả của tác vụ thứ nhất.Sử dụng
thenCombineđể kết hợp kết quả của haiCompletableFutuređộc lập và trả về kết quả cuối cùng.Sử dụng
allOfđể kết hợp baCompletableFuturevà in ra thông báo khi tất cả các tác vụ hoàn thành.Sử dụng
anyOfđể kết hợp baCompletableFuturevà in ra thông báo khi một trong các tác vụ hoàn thành trước.
Lời Khuyên và Best Practices
Kết hợp tác vụ một cách hợp lý: Sử dụng
thenComposevàthenCombineđể kết hợp các tác vụ một cách hợp lý, giúp tối ưu hóa luồng công việc và quản lý kết quả hiệu quả.Theo dõi trạng thái các tác vụ: Sử dụng
allOfvàanyOfđể theo dõi trạng thái hoàn thành của nhiều tác vụ không đồng bộ, giúp bạn kiểm soát luồng công việc tốt hơn.Xử lý ngoại lệ: Đảm bảo rằng bạn bắt và xử lý ngoại lệ trong các tác vụ không đồng bộ để tránh các lỗi không mong muốn.