Skip to main content

Command Palette

Search for a command to run...

Bài 4: Kết hợp nhiều CompletableFuture

Published
5 min readView as Markdown

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.supplyAsync tạo một tác vụ trả về chuỗi "Hello".

  • thenCompose tạo một CompletableFuture mới dựa trên kết quả của tác vụ trước, thêm " World" vào chuỗi.

  • thenAccept in 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.supplyAsync tạo hai tác vụ độc lập trả về các giá trị 2 và 3.

  • thenCombine kết hợp kết quả của hai tác vụ, cộng hai giá trị lại với nhau.

  • thenAccept in 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.allOf kết hợp cả ba CompletableFuture và tạo một CompletableFuture hoàn thành khi tất cả các tác vụ hoàn thành.

  • thenRun in 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.anyOf kết hợp cả ba CompletableFuture và tạo một CompletableFuture hoàn thành khi bất kỳ tác vụ nào hoàn thành trước.

  • thenAccept in 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

  1. Sử dụng thenCompose để kết hợp hai CompletableFuture theo 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.

  2. Sử dụng thenCombine để kết hợp kết quả của hai CompletableFuture độc lập và trả về kết quả cuối cùng.

  3. Sử dụng allOf để kết hợp ba CompletableFuture và in ra thông báo khi tất cả các tác vụ hoàn thành.

  4. Sử dụng anyOf để kết hợp ba CompletableFuture và 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 thenComposethenCombine để 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 allOfanyOf để 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.

More from this blog

devngu

169 posts