So sánh Runnable và Callable trong Java

Trong lập trình đa luồng Java, RunnableCallable là hai giao diện chính dùng để định nghĩa công việc thực thi trên các luồng. Tuy cùng mục đích, chúng có những khác biệt quan trọng về khả năng trả về giá trị và xử lý ngoại lệ.

Giao diện Runnable

Runnable là một functional interface với duy nhất phương thức run(), không trả về giá trị và không được phép ném ra checked exception.

public class Task implements Runnable {
    @Override
    public void run() {
        System.out.println("Thực thi tác vụ trong luồng con");
    }
}

Có thể khởi tạo và chạy tác vụ này qua đối tượng Thread:

public class App {
    public static void main(String[] args) {
        Thread worker = new Thread(new Task());
        worker.start();
    }
}

Từ Java 8 trở đi, nhờ đặc tính functional interface, Runnable có thể được biểu diễn gọn gàng bằng biểu thức lambda:

Thread t = new Thread(() -> {
    System.out.println("Tác vụ đơn giản với lambda");
});
t.start();

Giao diện Callable

Khác với Runnable, Callable<V> cho phép trả về kết quả kiểu V và có thể ném ra checked exception. Phương thức duy nhất của nó là call().

import java.util.concurrent.*;

public class ResultTask implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // Mô phỏng xử lý tốn thời gian
        Thread.sleep(1000);
        return 42;
    }
}

Để thực thi Callable, cần sử dụng ExecutorService. Kết quả được bao bọc trong đối tượng Future:

ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(new ResultTask());

try {
    Integer result = future.get(); // Chặn đến khi có kết quả
    System.out.println("Kết quả: " + result);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
} finally {
    executor.shutdown();
}

Dùng lambda cũng tương tự:

Callable<String> task = () -> {
    if (Math.random() < 0.5) throw new Exception("Lỗi ngẫu nhiên");
    return "Hoàn thành";
};

So sánh cốt lõi

  • Giá trị trả về: Runnablevoid; Callable → kiểu tham số hóa V.
  • Xử lý ngoại lệ: run() không được khai báo ném checked exception; call() thì có.
  • Cơ chế thực thi: Runnable có thể chạy trực tiếp qua Thread; Callable bắt buộc phải dùng ExecutorService.
  • Kết quả bất đồng bộ: Chỉ Callable hỗ trợ lấy kết quả thông qua Future.

Thẻ: Java multithreading Concurrency Runnable Callable

Đăng vào ngày 24 tháng 6 lúc 02:01