Khác ở giá trị trả về và cách lỗi được truyền đi.
Runnable.run() | Callable.call() | |
|---|---|---|
| Trả về | void | V (generic) |
| Checked exception | không ném được | throws Exception |
| Nộp cho pool | execute() hoặc submit() | chỉ submit() |
| Kết quả | không có | Future<V> |
java
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.execute(() -> load()); // Runnable: fire and forget
Future<Integer> f = pool.submit(() -> count()); // Callable: có kết quả
int n = f.get(); // block tới khi xongĐiểm dễ vấp trong thực tế: nếu task ném exception, execute(Runnable) đẩy lỗi ra UncaughtExceptionHandler (thường in ra log), còn submit(...) nuốt lỗi vào Future — bạn chỉ thấy nó khi gọi get(), lúc đó nhận ExecutionException bọc lỗi gốc.
Nộp task bằng submit() rồi không bao giờ đọc Future là cách phổ biến nhất làm mất exception.