Callable与Future可获取线程执行结果,Callable的call方法有返回值并能抛异常,而Runnable不能;通过ExecutorService提交Callable任务获得Future对象,调用其get方法获取结果,支持超时控制与异常处理,invokeAll可批量执行并获取多个结果,invokeAny返回首个完成任务的结果,需注意及时关闭线程池。

在Java多线程编程中,有时我们不仅希望启动一个线程去执行任务,还希望获取这个任务执行后的结果。传统的Runnable接口无法返回结果,而Callable与Future的组合正好解决了这个问题。本文将介绍如何使用Callable和Future来获取线程执行结果,并分享一些实用技巧。
Callable 与 Runnable 的区别
Callable是Java中用于定义可返回结果的异步任务的接口,它与Runnable的主要区别在于:
-
Callable的call()方法可以返回值,类型由泛型指定,如Callable -
call()方法可以抛出异常 -
Runnable的run()方法无返回值,也不能抛出受检异常
使用 Future 接收任务结果
Future是一个代表异步计算结果的接口。通过它,我们可以检查任务是否完成、等待结果或取消任务。通常,Callable任务提交给线程池后会返回一个Future对象。
示例代码:
立即学习“Java免费学习笔记(深入)”;
import java.util.concurrent.*;
public class CallableFutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// 定义一个Callable任务
Callable task = () -> {
Thread.sleep(2000);
return "任务执行完成";
};
// 提交任务,返回Future对象
Future future = executor.submit(task);
System.out.println("任务已提交,等待结果...");
try {
// get() 方法会阻塞,直到任务完成
String result = future.get(); // 可设置超时:future.get(3, TimeUnit.SECONDS)
System.out.println("结果:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
处理多个并发任务的返回值
当需要并发执行多个任务并收集结果时,可以使用ExecutorService的invokeAll()方法。它接收一个Callable集合,返回Future列表。
示例:
List> tasks = Arrays.asList( () -> { Thread.sleep(1000); return 1; }, () -> { Thread.sleep(2000); return 2; }, () -> { Thread.sleep(1500); return 3; } ); List > futures = executor.invokeAll(tasks); for (Future f : futures) { System.out.println(f.get()); // 依次输出1, 2, 3 }
也可以使用invokeAny(),它返回任意一个最先完成的任务的结果,适用于“哪个快用哪个”的场景。
优化与注意事项
-
避免长时间阻塞:调用
future.get()时建议使用带超时的版本,防止无限等待 -
及时关闭线程池:使用完
ExecutorService后调用shutdown()释放资源 -
异常处理:
get()可能抛出ExecutionException,需捕获并处理任务内部异常 -
取消任务:可通过
future.cancel(true)尝试中断正在运行的任务









