Runnable 的 run 方法没有返回值。如果异步任务需要返回结果,可以使用 Callable,结果由 Future 表示。
FutureTask
FutureTask 同时实现了 Runnable 和 Future,既可以交给线程执行,也可以用来获取结果:
import java.util.concurrent.FutureTask;
public class FutureTaskDemo {
public static void main(String[] args) throws Exception {
FutureTask<Integer> task = new FutureTask<>(() -> 21 * 2);
Thread worker = new Thread(task, "calculator");
worker.start();
System.out.println(task.get());
worker.join();
}
}输出 42。构造 FutureTask 不会自动启动任务,需要 start、提交给执行器,或者直接调用 run。直接 run 仍然是在调用线程中执行。
get 在结果还没准备好时会等待,所以“用了 Future”不代表整个调用过程完全不阻塞。提交完就立刻 get,调用方仍然会等这个结果。
异常、超时与取消
任务抛出的异常不会直接在提交任务那一行出现,get 会通过 ExecutionException 包装它,原异常可以从 getCause() 取得。
带超时的 get(timeout, unit) 只限制本次等待时间。抛出 TimeoutException 后,任务可能还在继续,需要另外决定是否取消。
import java.util.concurrent.CancellationException;
import java.util.concurrent.FutureTask;
public class FutureCancelDemo {
public static void main(String[] args) {
FutureTask<Integer> task = new FutureTask<>(() -> 42);
System.out.println(task.cancel(true));
task.run();
System.out.println(task.isDone());
try {
task.get();
} catch (CancellationException e) {
System.out.println("任务已取消");
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}这里在执行前取消,输出 true、true、任务已取消,任务体不会执行。isDone() 表示进入结束状态,不保证成功,也包括异常和取消。
任务已经运行时,cancel(true) 会尝试中断执行线程,但任务仍需配合响应中断。它不能强制停止一段忽略中断的计算或任意外部操作。即使 Future 显示已取消,执行代码也可能还在退出过程中。
多个任务的结果顺序
把多个 Future 放进列表,按提交顺序逐个 get,前面较慢的任务会拖住已经完成的后面任务。
需要按完成顺序处理时,可以使用 ExecutorCompletionService。它把完成的任务放入一个完成队列,调用方通过 take 取得先完成的 Future,再 get 结果。
Future 解决了结果、异常和取消的表示,但多个任务之间的依赖还需要调用方组织。一个结果出来再触发下一个任务的场景,后面可以用 CompletableFuture 表达。