CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Mục lục

Trang chủBlogHiểu rõ Callable và Futur...
Java

Hiểu rõ Callable và Future trong Java qua ví dụ thực tế

3 phút đọc21/07/2025
CyStack Author
Bao Tran

Web Developer

0 lượt xem
Reading Time: 3 minutes

Callable và Future trong Java được sử dụng rất nhiều trong lập trình đa luồng. Trong những bài viết trước, chúng ta đã tìm hiểu nhiều về các luồng (thread) trong Java nhưng đôi khi chúng ta lại muốn có một luồng có thể trả về một giá trị nào đó để sử dụng. Từ Java 5, gói concurrency đã giới thiệu **interface java.util.concurrent.Callable trong gói concurrency, tương tự như interface Runnable, nhưng điểm khác biệt là nó có thể trả về một đối tượng bất kỳ và có thể ném ra Exception.

Callable và Future trong Java

Java Callable là gì?

Interface Callable trong Java sử dụng Generic để định nghĩa kiểu dữ liệu trả về. Lớp Executors cung cấp các phương thức hữu ích để thực thi một Callable trong một thread pool (bộ quản lý luồng). Vì các tác vụ Callable chạy song song nên chúng ta cần chờ kết quả trả về từ các đối tượng này.

Java Future là gì?

Các tác vụ Callable trong Java trả về một đối tượng java.util.concurrent.Future. Thông qua đối tượng Future, chúng ta có thể kiểm tra trạng thái của tác vụ Callable và lấy về kết quả mà nó trả về.

Future cung cấp phương thức get() có thể đợi cho đến khi Callable hoàn tất rồi mới trả về kết quả. Ngoài ra, Future còn cung cấp phương thức cancel() để hủy bỏ tác vụ Callable đang được liên kết. Có một phiên bản nạp chồng (overloaded) của phương thức get(), cho phép chỉ định thời gian chờ kết quả, giúp tránh việc luồng hiện tại bị chặn (blocked) quá lâu. Ngoài ra còn có các phương thức isDone()isCancelled() để kiểm tra trạng thái hiện tại của tác vụ Callable.

Dưới đây là một ví dụ đơn giản về tác vụ Callable trả về tên của luồng đang thực thi sau một giây. Chúng ta sử dụng Executor framework để thực thi 100 tác vụ song song và dùng Future để nhận kết quả từ các tác vụ đã được gửi đi.

Javapackage com.journaldev.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyCallable implements Callable {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        // trả về tên của thread đang thực thi tác vụ callable này
        return Thread.currentThread().getName();
    }

    public static void main(String args[]) {
        // Lấy ExecutorService từ lớp tiện ích Executors, với thread pool có kích thước là 10
        ExecutorService executor = Executors.newFixedThreadPool(10);
        // tạo một danh sách để giữ các đối tượng Future liên quan đến Callable
        List> list = new ArrayList>();
        // Tạo một instance của MyCallable
        Callable callable = new MyCallable();
        for (int i = 0; i < 100; i++) {
            // gửi các tác vụ Callable để được thực thi bởi thread pool
            Future future = executor.submit(callable);
            // thêm Future vào danh sách, chúng ta có thể lấy giá trị trả về qua Future
            list.add(future);
        }
        for (Future fut : list) {
            try {
                // in ra giá trị trả về của Future, chú ý độ trễ của output trong console
                // vì Future.get() sẽ đợi cho đến khi tác vụ hoàn thành
                System.out.println(new Date() + "::" + fut.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        // tắt executor service
        executor.shutdown();
    }
}

Sau khi chạy chương trình chạy, bạn sẽ thấy có độ trễ trong đầu ra vì phương thức get() của Future sẽ chờ cho tác vụ Callable hoàn tất. Đồng thời, chỉ có 10 luồng đang thực thi các tác vụ này. Đây là một đoạn output của chương trình trên:

Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...

Mẹo: Vậy nếu chúng ta muốn ghi đè (override) một số phương thức của interface Future thì sao? Chẳng hạn như ghi đè phương thức get() để nó tự động hết hạn sau một khoảng thời gian mặc định thay vì chờ vô thời hạn thì chúng ta có thể sử dụng lớp FutureTask của Java vì đây là lớp triển khai cơ bản của interface Future.

Về tác giả

Bao Tran
Bao TranWeb Developer

I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.

Cập nhật thông tin mới nhấtNhận các thông tin mới nhất về mối đe dọa, báo cáo an ninh mạng từ CyStack về hòm thư điện tử của bạn

Thảo luận (0)

Đăng nhập để thảo luận

Bài viết liên quan