VieTopik
Tiếng HànTiếng Anh.NET (C#)Java
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
Java CoreCông cụ hằng ngày
Bài 19/19
5 phút

CompletableFuture cơ bản

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Gọi API thanh toán, đọc database, tải file: những việc này mất từ vài chục mili giây tới vài giây. Bài này hướng dẫn cách chạy việc chậm mà không chặn luồng đang chạy, bằng CompletableFuture.

Khái niệm

📨 CompletableFuture: object đại diện cho một việc đang chạy và sẽ xong sau.

CompletableFuture<T> là việc sẽ trả về một giá trị kiểu T.

⏳ supplyAsync/join: supplyAsync chạy một lambda ở luồng khác và trả về ngay một CompletableFuture, join đứng chờ việc đó xong rồi lấy kết quả.

Ví dụ

// Main.java
void main() {
    long price = getPriceAsync("PEN-01").join();
    System.out.println(price);   // 5000
}

CompletableFuture<Long> getPriceAsync(String code) {
    // chờ 1 giây rồi mới chạy: giả lập gọi mạng
    Executor later = CompletableFuture.delayedExecutor(
        1, TimeUnit.SECONDS);
    return CompletableFuture.supplyAsync(
        () -> 5000L, later);
}
  • Kiểu trả về là CompletableFuture<Long> chứ không phải long. Lúc method trả về, việc tra giá chưa xong.
  • supplyAsync(() -> 5000L, later) chạy lambda ở luồng khác. later chờ 1 giây rồi mới chạy lambda, dùng để giả lập việc chậm.
  • Tên method kết thúc bằng Async để nơi gọi biết kết quả chưa có ngay, như chính supplyAsync.
  • join() lấy ra giá trị Long từ CompletableFuture<Long>.
  • Muốn xử lý tiếp kết quả mà không đứng chờ, dùng thenApply(p -> ...): lambda chạy khi có kết quả.
getPriceAsync(PEN-01) supplyAsync, hẹn 1 giây sau trả về CompletableFuture chưa xong sau 1 giây: 5000 System.out.println(price) join, đứng chờ kết quả main getPriceAsync
Thứ tự chạy của ví dụ trên

Thử ngay

Dán vào Main.java rồi chạy java Main.java:

// Main.java
void main() {
    System.out.println("1. Bắt đầu");
    CompletableFuture<Long> task =
        getPriceAsync("PEN-01");
    System.out.println("2. Đã gọi, chưa chờ");

    System.out.println("3. Giá: " + task.join());
}

CompletableFuture<Long> getPriceAsync(String code) {
    System.out.println("   đang tra giá...");
    Executor later = CompletableFuture.delayedExecutor(
        500, TimeUnit.MILLISECONDS);
    return CompletableFuture.supplyAsync(() -> {
        System.out.println("   tra xong");
        return 5000L;
    }, later);
}

Đoán trước khi chạy: dòng "2. Đã gọi, chưa chờ" in trước hay sau "tra xong"?

Xem kết quả
1. Bắt đầu
   đang tra giá...
2. Đã gọi, chưa chờ
   tra xong
3. Giá: 5000

In trước. Gọi getPriceAsync thì dòng "đang tra giá..." in ngay, rồi supplyAsync trả về nơi gọi mà không đợi việc tra giá.

Chương trình in dòng 2 trong lúc việc tra giá vẫn đang chờ. Chỉ tới task.join() mới thật sự đứng đợi kết quả.

Lỗi hay gặp

Quên join. Không có join thì bạn nhận về CompletableFuture, không phải giá trị.

// SAI — lỗi compile: thiếu join()
long price = getPriceAsync("PEN-01");
// ĐÚNG
long price = getPriceAsync("PEN-01").join();

Gọi join ngay để xử lý tiếp. join chặn luồng hiện tại cho tới khi có kết quả. Trong ứng dụng web, việc này làm server chậm đi, có khi treo hẳn.

// SAI — chặn luồng trong lúc chờ giá
long price = getPriceAsync("PEN-01").join();
long withVat = price * 110 / 100;
// ĐÚNG — thenApply không chặn luồng
CompletableFuture<Long> withVat =
    getPriceAsync("PEN-01")
        .thenApply(p -> p * 110 / 100);
System.out.println(withVat.join());   // 5500

Tóm tắt

  • CompletableFuture<T> là việc sẽ trả về T khi xong.
  • supplyAsync chạy lambda ở luồng khác và trả về ngay, join chờ rồi lấy kết quả.
  • thenApply xử lý tiếp kết quả khi có mà không chặn luồng.
  • Chỉ join ở nơi thật sự cần kết quả, như cuối main.

Tự kiểm tra

0/3 câu
Câu 1

Method chạy việc chậm ở luồng khác nhưng không trả về giá trị nào nên khai báo kiểu trả về là gì?

Câu 2

CompletableFuture<String> getNameAsync() trả về "An". Dòng nào lấy đúng chuỗi "An"?

Câu 3

Việc nào nên chạy bằng CompletableFuture?

Exception

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt